Compare commits

..

1926 commits
0.2.2 ... main

Author SHA1 Message Date
Hugo Osvaldo Barrera
c3262d88cc Mark unused variables as such 2025-11-06 01:05:48 +01:00
cbb4e314f6 cli/discover: add implicit config to pair for collection creation
Adds support for auto-creating collections when they exist only on
one side and `implicit = 'create'` is set in the pair config.
2025-11-06 00:04:22 +00:00
Hugo Osvaldo Barrera
ac9919d865 Add changelog entry for latest commits 2025-10-09 11:05:33 +02:00
samm81
b124ce835b fix: remove unused import 2025-10-09 09:02:01 +00:00
samm81
6708dbbbdc fix: fix ssl behavior in request
- `ClientConnectionError` in `aiohttp` can wrap SSL handshake and
  certificate verification errors
- Retrying those hides the real cause and produced
  `TransientNetworkError` instead of the expected certificate error
- Removing `ClientConnectionError` from the transient list lets SSL
  errors surface correctly
2025-10-09 09:02:01 +00:00
samm81
81d8444810 http: refactor auth loop 2025-10-09 09:02:01 +00:00
samm81
4990cdf229 http: retry safe DAV methods on transient aiohttp disconnects; cli: gather with return_exceptions to allow in-flight backoffs to finish
- Retry ServerDisconnectedError/ServerTimeoutError/ClientConnectionError/asyncio.TimeoutError for GET/HEAD/OPTIONS/PROPFIND/REPORT
- Keep original rate-limit handling (429, Google 403 usageLimits)
- In CLI, avoid cancelling sibling tasks so per-request backoff can complete; re-raise first failure after all tasks finish
2025-10-09 09:02:01 +00:00
Hugo Osvaldo Barrera
4c2c60402e ci: run ruff and mypy
Fixes: https://github.com/pimutils/vdirsyncer/issues/1194
2025-09-20 13:53:39 +02:00
Hugo Osvaldo Barrera
2f4f4ac72b Fix some mypy type failures 2025-09-20 13:51:21 +02:00
Hugo Osvaldo Barrera
6354db82c4 make: install check requirements via install-dev 2025-09-20 13:19:41 +02:00
Hugo Osvaldo Barrera
a9b6488dac Merge docs-requirements.txt into pyproject.toml
Keep requirements definitions all in one place.
2025-09-20 13:18:17 +02:00
Hugo Osvaldo Barrera
a4ceabf80b Organise imports
And update imports from deprecated locations.
2025-09-20 13:05:14 +02:00
Hugo Osvaldo Barrera
3488f77cd6 Remove unused variables 2025-09-20 13:05:14 +02:00
Hugo Osvaldo Barrera
19120422a7 Use ternary operator for trivial assignment 2025-09-20 13:05:14 +02:00
Hugo Osvaldo Barrera
2e619806a0 Drop support for Python 3.8
Note that recent commits introduced syntax unsupported by Python 3.8
already.
2025-09-20 13:05:03 +02:00
Hugo Osvaldo Barrera
4669bede07 Organise imports 2025-09-20 12:56:22 +02:00
Hugo Osvaldo Barrera
59c1c55407 Document wrapper 2025-09-20 12:50:00 +02:00
Hugo Osvaldo Barrera
1502f5b5f4 Execute one assertion per line 2025-09-20 12:45:56 +02:00
Hugo Osvaldo Barrera
a4d4bf8fd1 Normalise pytest syntax 2025-09-20 12:45:56 +02:00
Hugo Osvaldo Barrera
aab70e9fb0 Use cached_property from the stdlib
Our local implementation preceded the one in the stdlib, but we no
longer support versions of Python which do not ship it.
2025-09-20 12:45:56 +02:00
Hugo Osvaldo Barrera
ed88406aec Avoid using mutable class attributes
A tuple works fine here.
2025-09-20 12:45:56 +02:00
Hugo Osvaldo Barrera
ffe883a2f1 Avoid warning due to unused import 2025-09-20 12:45:56 +02:00
Hugo Osvaldo Barrera
e5f2869580 ruff: ignore block for legacy Python 2025-09-20 12:45:56 +02:00
Hugo Osvaldo Barrera
95bb7bd7f9 Declare functions instead of assigning to lambdas 2025-09-20 12:45:56 +02:00
Hugo Osvaldo Barrera
e3b2473383 Use list expansion instead of concatenation 2025-09-20 12:45:56 +02:00
Hugo Osvaldo Barrera
424cfc5799 ruff: ignore false positive 2025-09-20 12:45:56 +02:00
Hugo Osvaldo Barrera
29312e87c5 Close status even if assertions fail 2025-09-20 12:45:56 +02:00
Hugo Osvaldo Barrera
c77b22334a Add changelog entry for latest change 2025-09-20 12:42:10 +02:00
samm81
02350c924b
http(request): collates status checks 2025-09-13 16:23:46 +07:00
Samuel Maynard
605f878f9b
test_retry: remove unneeded decorator
Co-authored-by: Hugo <hugo@whynothugo.nl>
2025-09-13 12:22:25 +03:00
samm81
bb2b71da81
builds(archlinux-py313): adds python-tenacity package 2025-09-12 17:02:28 +07:00
samm81
065ebe4752
AUTHORS: add samm81 2025-09-12 16:25:00 +07:00
samm81
0d741022a9
http: add rate limiting (mainly for google)
- google calendar uses the `403` and `429` codes to perform rate limiting [1][2]. this pr adds `tenacity` to perform exponential back off as suggested in google calendar's docs [3].

[1]: https://developers.google.com/workspace/calendar/api/guides/errors#403_rate_limit_exceeded
[2]: https://developers.google.com/workspace/calendar/api/guides/errors#429_too_many_requests
[3]: https://developers.google.com/workspace/calendar/api/guides/quota#backoff
2025-09-12 16:20:44 +07:00
Hugo Osvaldo Barrera
b5d3b7e578 Apply auto-fixes for RUF rule 2025-08-29 10:17:44 +02:00
Hugo Osvaldo Barrera
9677cf9812 Simplify some statements 2025-08-29 10:17:44 +02:00
Hugo Osvaldo Barrera
6da84c7881 ruff: sort rules 2025-08-29 10:17:44 +02:00
Hugo Osvaldo Barrera
dceb113334 ruff: fix mix-up in configuration
Ruff hasn't been finding errors in a while. Most of them are linting
checks anyway, but there was quite a bit of deprecated usages.
2025-08-29 10:17:44 +02:00
Hugo Osvaldo Barrera
01fa614b6b Fix line which are too long 2025-08-29 10:17:41 +02:00
Hugo Osvaldo Barrera
20cc1247ed ruff: apply auto-fixes 2025-08-29 10:03:24 +02:00
Дилян Палаузов
2f548e048d Some code simplifications with the return statement 2025-08-29 09:48:27 +02:00
Jakub Klinkovský
5d343264f3 Remove python-requests-toolbelt from Arch Linux build
The dependency was dropped in 89a01631fa
2025-08-29 09:28:50 +02:00
Hugo Osvaldo Barrera
bc3fa8bd39 Remove stale references to setup.py 2025-08-28 22:57:55 +02:00
Hugo Osvaldo Barrera
8803d5a086 ruff: use extend-select
Ensure that we don't disable any default rules.
2025-08-28 11:40:46 +02:00
Hugo Osvaldo Barrera
96754a3d0a ruff: enable TID rules 2025-08-28 11:39:06 +02:00
Hugo Osvaldo Barrera
d42707c108 Bump constraint for aiostream
There's a newer version available, and it also doesn't have any breaking
changes which could affect us.
2025-08-28 11:37:14 +02:00
Hugo Osvaldo Barrera
ddfe3cc749 Bump constraint for aiostream
Fixes: https://github.com/pimutils/vdirsyncer/issues/1111
2025-08-28 11:32:28 +02:00
Radon Rosborough
84ff0ac943 Log error response body in debug 2025-08-27 09:11:32 +02:00
Hugo Osvaldo Barrera
388c16f188 Document sqlite fix in changelog 2025-08-25 17:37:26 +02:00
Hugo Osvaldo Barrera
78f41d32ce Explicitly close status database
Using `__del__` often closes the database on a different thread, which
is not supported by the sqlite module and produces a different warning.

Explicitly close the status database everywhere it is used.
2025-08-25 17:33:20 +02:00
Hugo Osvaldo Barrera
164559ad7a Remove references to obsolete event_loop fixture
It's gone from the latest pytest-asyncio.
2025-08-25 17:12:21 +02:00
samm81
2c6dc4cddf updates SqliteStatus to properly close connections
otherwise, when trying to run `pytest` in a `python3.13` environment
results in a bunch of

```
tests/unit/sync/test_sync.py::test_partial_sync_ignore
  /home/user/.asdf/installs/python/3.13.1/lib/python3.13/asyncio/base_events.py:650: ResourceWarning: unclosed database in <sqlite3.Connection object at 0x7fda8f6b6c50>
    sys.set_asyncgen_hooks(
  Enable tracemalloc to get traceback where the object was allocated.
  See https://docs.pytest.org/en/stable/how-to/capture-warnings.html#resource-warnings for more info.
  ```
2025-08-25 16:53:00 +02:00
samm81
9bbb7fa91a fix: fix mypy typing error 2025-08-25 16:51:29 +02:00
Hugo Osvaldo Barrera
f8bcafa9d7 ci: use Alpine 3.19 for Python 3.11 2025-08-25 16:49:16 +02:00
Hugo Osvaldo Barrera
162879df21 ci: include python version in job name 2025-07-23 23:24:35 +02:00
Hugo Osvaldo Barrera
3b9db0e4db Add support for Python 3.13
Fixes: https://github.com/pimutils/vdirsyncer/issues/1180
2025-07-23 23:23:59 +02:00
Hugo Osvaldo Barrera
63d2e6c795 pyproject: squelch warning 2025-04-11 01:59:29 +02:00
Hugo Osvaldo Barrera
03d1c4666d pyproject: update syntax for licence 2025-04-11 01:59:17 +02:00
Hugo Osvaldo Barrera
ecdd565be4 Document checkfile() 2025-04-09 14:00:40 +02:00
Hugo Osvaldo Barrera
17e43fd633 Move test dependencies into pyproject.toml 2025-04-07 18:47:44 +02:00
Hugo Osvaldo Barrera
2b4496fea4 Update linting tools 2025-04-07 18:42:07 +02:00
Hugo Osvaldo Barrera
fc4a02c0c9 Add some missing type hints 2025-04-07 18:40:34 +02:00
Hugo Osvaldo Barrera
c19802e4d8 Configure ruff as an auto-formatter 2025-04-07 18:40:34 +02:00
Hugo Osvaldo Barrera
cce8fef8de Auto-format using ruff 2025-04-07 18:40:34 +02:00
Hugo Osvaldo Barrera
9a0dbc8cd0 Update ruff configuration syntax 2025-04-07 18:40:34 +02:00
Hugo Osvaldo Barrera
32453cccfc Drop support for Python 3.7
Installing on Python 3.7 no longer works due to lack of support in the
minimal version of setuptools_scm. This commit makes the change
official, but it happened a while ago.
2025-04-07 18:39:52 +02:00
Hugo Osvaldo Barrera
057f3af293 Remove stale GitLab CI config 2025-04-07 18:35:12 +02:00
Hugo Osvaldo Barrera
e76d8a5b03 Add two more trove classifiers 2025-04-07 18:09:36 +02:00
Hugo Osvaldo Barrera
d8961232c4 Remove setup.py in favour of pyproject.toml
Implements: https://github.com/pimutils/vdirsyncer/issues/1164
2025-04-07 18:06:45 +02:00
Hugo Osvaldo Barrera
646e0b48a5 Delete stale comment 2025-04-07 18:01:16 +02:00
Hugo Osvaldo Barrera
fb6a859b88 Add changelog entry for recent change 2025-04-07 17:39:18 +02:00
Petr Moucha
ff999b5b74 Use proxy configuration from environment for Google storage 2025-04-04 13:17:32 +02:00
Hugo Osvaldo Barrera
41b48857eb Remove reference to dead domain 2025-03-06 11:57:05 +01:00
Hugo Osvaldo Barrera
70d09e6d5d Remove stale comment 2025-02-13 13:42:06 +01:00
Ben Boeckel
8b063c39cb atomicwrites: remove dependency on abandoned library 2025-02-13 13:37:06 +01:00
Hugo Osvaldo Barrera
12a06917db Add explicit configuration for readthedocs
See: https://about.readthedocs.com/blog/2024/12/deprecate-config-files-without-sphinx-or-mkdocs-config/
2025-02-13 13:34:13 +01:00
Hugo Osvaldo Barrera
2fee1d67f2 Update CI job with "oldest supported dependencies"
Alpine 3.17 has faded away, bump to Alpine 3.18.
2025-02-13 13:32:59 +01:00
Hugo Osvaldo Barrera
a934d5ec66 Keep test for duplicate consecutive keys
See: https://github.com/pimutils/vdirsyncer/pull/1153
2024-12-21 16:49:50 +01:00
Colin Watson
c79d3680cd Fix _Component.__delitem__ with adjacent identical keys
Hypothesis found the following example:

```
tests/unit/utils/test_vobject.py:335: in add_prop
    assert c[key] == value
E   AssertionError: assert '0' == '1'
E
E     - 1
E     + 0
E   Falsifying example:
E   state = VobjectMachine()
E   unparsed_0 = state.get_unparsed_lines(encoded=False, joined=False)
E   parsed_0 = state.parse(unparsed=unparsed_0)
E   state.add_prop_raw(c=parsed_0, key='0', params=[], value='0')
E   state.add_prop_raw(c=parsed_0, key='0', params=[], value='0')
E   state.add_prop(c=parsed_0, key='0', value='1')
E   state.teardown()
```

After the two `add_prop_raw` calls, `c.props` is `["0;:0", "0;:0",
"FOO:YES"]`.  `_Component.__delitem__` then fails to effectively delete
the previous key: it deletes the first `"0;:0"` item, but then checks
for continuation lines following it and incorrectly keeps the second
`"0;:0"` item even though it begins with one of the prefixes it's trying
to delete.  Checking for the prefix in the check for continuation lines
fixes this.

Fixes: #1149
2024-12-20 01:43:15 +00:00
Hugo Osvaldo Barrera
cd050d57b9 Use direnv to set up a virtualenv for development 2024-12-09 14:18:24 +01:00
Hugo Osvaldo Barrera
8c98992f74 Move setuptools-scm config into pyproject.toml 2024-12-09 14:18:06 +01:00
Hugo Osvaldo Barrera
c2eed9fb59 Add a readthedocs configuration file
Used for building docs in CI pipelines.
2024-12-09 01:36:22 +01:00
Mike A.
a490544405 Do not load netrc config files 2024-12-09 01:32:29 +01:00
Hugo Osvaldo Barrera
688d6f907f Update deprecated usages of hypothesis 2024-12-09 01:30:44 +01:00
euxane
2e7e31fdbf storage/http: add support for filter_hook
This allows users to process fetched items through a filter command,
to fix malformed webcal items as they are imported.

In my case, my provider adds the export time to the description and
random sequence numbers to all events. This caused the whole collection
to be invalidated and propagated at each sync. I use the filter to
remove those, canonicalising the items.
2024-12-08 19:31:32 +01:00
Arran Ubels
616d7aacb0 OfflineIMAP url Update 2024-10-31 22:43:45 +01:00
Hugo Osvaldo Barrera
89129e37b6 Typo
Fixes: https://github.com/pimutils/vdirsyncer/issues/1139
2024-09-13 18:36:17 +02:00
Hugo Osvaldo Barrera
88722ef4b7 Add changelog entry for Digest Auth 2024-09-11 17:25:29 +02:00
Mike A.
35f299679f Rewrite guess auth test for unsupported status 2024-09-11 12:04:05 +02:00
Mike A.
67e1c0ded5 Make tests pass 2024-09-11 12:04:05 +02:00
Mike A.
89a01631fa Remove requests_toolbelt 2024-09-11 12:04:05 +02:00
Mike A.
611b8667a3 Implement digest auth 2024-09-11 12:04:05 +02:00
Hugo Osvaldo Barrera
8550475548 Formatting 2024-08-26 12:49:36 +02:00
Hugo Osvaldo Barrera
cd2445b991 Upgrade Alpine release used in CI 2024-08-26 12:49:24 +02:00
Jakub Klinkovský
5ca2742271 Add short option for the help option 2024-08-26 12:43:20 +02:00
Jakub Klinkovský
5ac9dcec29 Update documentation regarding SSL pinning by fingerprint 2024-08-16 15:18:18 +02:00
octvs
a513a7e4fa docs: update config info on todoman tutorial 2024-04-02 15:30:16 +02:00
Dick Marinus
5ae05245e6 fix pylint W0621: Redefining name 'main' from outer scope (line 68) (redefined-outer-name) 2024-03-19 09:59:08 +01:00
Hugo Osvaldo Barrera
055ed120dd Pre-commit autoupdate 2024-02-20 15:08:51 +01:00
Hugo Osvaldo Barrera
31816dc652 Add some type hints 2024-02-20 15:08:51 +01:00
Bleala
2e023a5feb Update AUTHORS.rst 2024-02-16 14:29:11 +01:00
Bleala
14afe16a13 Update CHANGELOG.rst 2024-02-16 14:29:11 +01:00
Bleala
5766e1c501 Add Docker Environment 2024-02-16 14:29:11 +01:00
Xavier Brochard
fade399a21 more explanations of "collection" meaning 2024-02-02 10:26:49 +01:00
Xavier Brochard
3433f8a034 A bit more explanation of "from a" and "from b" 2024-02-02 10:25:10 +01:00
chrisblech
6a3077f9dc add pre_deletion_hook
closes https://github.com/pimutils/vdirsyncer/issues/1107
2024-01-31 19:14:59 +01:00
Hugo Osvaldo Barrera
42c5dba208 Pre-commit autoupdate 2024-01-31 19:08:25 +01:00
Hugo Osvaldo Barrera
7991419ab1 Merge implicitly concatenated strings 2024-01-31 19:08:25 +01:00
Hugo Osvaldo Barrera
03e6afe9dc Remove broken contact link
Fixes: https://github.com/pimutils/vdirsyncer/issues/1104
2024-01-28 20:15:08 +01:00
Hugo
762d369560
Merge pull request #1103 from jasonccox/main
Require matching BEGIN and END lines in vobjects
2024-01-28 20:13:28 +01:00
Hugo Osvaldo Barrera
2396c46b04 Allow specifying deb distro/ver via env vars 2023-12-18 14:35:48 +01:00
Hugo Osvaldo Barrera
b626236128 Use docker (instead of podman) to build debs 2023-12-18 14:35:48 +01:00
Hugo Osvaldo Barrera
45b67122fe Fast-mail publishing if credentials are missing 2023-12-18 14:35:48 +01:00
Jason Cox
7a387b8efe Require matching BEGIN and END lines in vobjects
Raise an error when parsing a vobject that has mismatched `BEGIN` and
`END` lines (e.g., `BEGIN:FOO` followed by `END:BAR`) or missing `END`
lines (e.g., `BEGIN:FOO` with no subsequent `END:FOO`).

Fixes #1102.
2023-12-13 10:31:32 -05:00
Kai Herlemann
889e1f9ea2 Implement a no_delete flag
See: https://github.com/pimutils/vdirsyncer/pull/1090
2023-11-29 23:50:32 +08:00
azrdev
d1f93ea0be docs: add instructions to get pw from environment variable
tested with vdirsyncer 0.19.2 on archlinux
2023-11-26 08:20:20 +01:00
Hugo Osvaldo Barrera
82fd03be64 Clarify that pipx won't install man pages
And reword the section a bit.
2023-11-16 07:19:15 +08:00
Hugo Osvaldo Barrera
b50f9def00 Ensure type annotations are backwards compatible
Related: https://github.com/pimutils/todoman/issues/544
2023-10-29 16:04:23 +01:00
Hugo Osvaldo Barrera
91c16b3215 Add a changelog entry for vcard 4.0 support 2023-10-07 03:26:04 +02:00
wrvsrx
d45ae04006 Update doc about use_vcard_4 2023-10-06 23:18:26 +02:00
wrvsrx
9abf9c8e45 Add an option to use vCard 4.0
Fix #503
2023-10-06 23:18:21 +02:00
Hugo Osvaldo Barrera
0f0e5b97d3 Ignore type checking lines in coverage report 2023-09-25 16:24:52 +02:00
Hugo Osvaldo Barrera
301aa0e16f pre-commit run --all 2023-09-24 12:41:56 +02:00
Hugo Osvaldo Barrera
dcd3b7a359 pre-commit autoupdate 2023-09-24 12:35:40 +02:00
Hugo Osvaldo Barrera
df8c4a1cf5 pre-commit: fix ruff hook being a no-op 2023-09-24 12:35:16 +02:00
suiso67
5a17ec1bba Fix wrong document formatting 2023-09-08 13:03:00 +02:00
suiso67
ab3aa108fc Fix broken Arch Linux package link 2023-09-08 13:03:00 +02:00
Justin !
f194bb0a4c Do not allow None value if we assert they're not None on the next line
This change imply changing the `save_status` parameters order. If you
don't like that, I can drop this commit.
2023-08-23 16:20:21 +02:00
Justin !
c073d55b2f Don't allow load_status to return None 2023-08-23 16:20:21 +02:00
Justin !
3611e7d62f Add type hint to vdirsyncer/cli/utils.py 2023-08-23 16:20:21 +02:00
Jan Moeller
adc974bdd1 docs: add changelog for #1081 2023-08-06 12:45:42 +02:00
Jan Moeller
efad9eb624 fix(repair_collection): use DiscoverResult logic to discover collection
fixes error: `DAVSession.__init__() missing 1 required keyword-only argument:
'connector'`.
Reuses the existing logic in DiscoverResult to determine if the storage requires
a 'connector' arg.
2023-08-06 12:45:42 +02:00
pre-commit-ci[bot]
246568f149 [pre-commit.ci] auto fixes from pre-commit.com hooks
for more information, see https://pre-commit.ci
2023-07-14 11:55:08 +02:00
Justin !
439f1e6f50 Run ruff --fix vdirsyncer 2023-07-14 11:55:08 +02:00
Justin !
ef8e8980d1 Add Typing annotation to cli/config.py 2023-07-14 11:55:08 +02:00
Justin !
08616abbb5 Add typing annotation to cli/__init__.py 2023-07-14 11:55:08 +02:00
Hugo Osvaldo Barrera
4237ff863c Slightly improve docs for configuring google 2023-07-13 12:34:57 +02:00
Hugo Osvaldo Barrera
1a6ad54543 ci: Standardise jobs a bit 2023-07-13 12:33:58 +02:00
Claudio Noguera
203468fd25 Update config.rst
This is the way it actually works.
With web application, a 400 is returned. With desktop it works fine
2023-07-13 12:32:00 +02:00
Hugo Osvaldo Barrera
6368af1365 ci: remove superfluous export
We're now using a virtualenv.
2023-06-26 19:25:53 +02:00
Hugo Osvaldo Barrera
b38306bdd0 ci: Ensure that minimal job runs on older Python
Fixes: https://github.com/pimutils/vdirsyncer/issues/1077
2023-06-26 19:25:40 +02:00
Hugo Osvaldo Barrera
d26557bee3 Python 3.10 and 3.11 are also supported
We've been running 3.11 on CI for a while now.
2023-06-26 19:04:23 +02:00
Hugo Osvaldo Barrera
b9f749467c Add forward-compatibility for storage type parameter
The Rust rewrite of vdirsyncer requires explicitly specifying what type
of "filesystem" storage is being used. These can be either
"filesystem/icalendar" or "filesystem/vcard".

Add forward-compatibility with this upcoming format, by allowing (but
ignoring) a slash and anything after it.

This makes configuration files that have been updated for the Rust
implementation compatible with the Python implementation.

Closes: https://github.com/pimutils/vdirsyncer/pull/1075
2023-06-26 19:01:52 +02:00
Hugo Osvaldo Barrera
7e5910a341 ci: use virtualenvs for jobs that use pip
Pip now refuses to tamper with the system python installation.
2023-06-26 19:00:32 +02:00
Hugo Osvaldo Barrera
7403182645 Update changelog with recent updates 2023-06-26 18:50:00 +02:00
Henning Sudbrock
bad381e5ba Fix link to GNU Guix package in documentation
Fixes #1071
2023-05-21 10:47:07 +02:00
pre-commit-ci[bot]
700586d959 [pre-commit.ci] pre-commit autoupdate
updates:
- [github.com/psf/black: 23.1.0 → 23.3.0](https://github.com/psf/black/compare/23.1.0...23.3.0)
- [github.com/pre-commit/mirrors-mypy: v1.0.1 → v1.2.0](https://github.com/pre-commit/mirrors-mypy/compare/v1.0.1...v1.2.0)
- [github.com/charliermarsh/ruff-pre-commit: v0.0.249 → v0.0.265](https://github.com/charliermarsh/ruff-pre-commit/compare/v0.0.249...v0.0.265)
2023-05-09 11:52:48 +02:00
Hugo Osvaldo Barrera
c1d3efb6b8 Make broken test as xfail 2023-05-09 11:52:48 +02:00
Hugo Osvaldo Barrera
c55b969791 Add some type hints 2023-05-09 11:52:48 +02:00
Florian Preinstorfer
079a156bf8 Remove superflous string quotes 2023-03-30 14:03:32 +02:00
Hugo Osvaldo Barrera
242216d85a Brain typo 2023-03-28 23:23:44 +02:00
Hugo Osvaldo Barrera
b1ef68089b Properly populate cache during SingleFileStorage._at_once
The call to `list` was never awaited and the stream never drained, so
the cache remained empty.
2023-03-10 12:27:48 +01:00
Enrico Guiraud
85ae33955f
Prevent single file storage from performing unnecessary N^2 loop
For single file storage we wrap the logic of get_multi with the
at_once context manager so that `self.list()` (which is called by
`self.get()`) actually caches the items rather than re-computing
them at every call.

This should largely mitigate the performance issue describe at
https://github.com/pimutils/vdirsyncer/issues/818 . The issue
discussion also contains more background about this patch.
2023-03-09 17:59:20 -06:00
Timo Ludwig
54a90aa5dd Document caveats of Google contacts storage
- Group labels are not mapped to CATEGORIES property
- BDAY property is missing when date is incomplete
2023-03-06 09:57:00 +01:00
Hugo Osvaldo Barrera
443ae3d3e7 Fix crash when using auth certs
Fixes: https://github.com/pimutils/vdirsyncer/issues/1033
2023-02-28 16:21:28 +01:00
pre-commit-ci[bot]
3bf9a3d684 [pre-commit.ci] pre-commit autoupdate
updates:
- [github.com/pre-commit/mirrors-mypy: v1.0.0 → v1.0.1](https://github.com/pre-commit/mirrors-mypy/compare/v1.0.0...v1.0.1)
- [github.com/charliermarsh/ruff-pre-commit: v0.0.246 → v0.0.249](https://github.com/charliermarsh/ruff-pre-commit/compare/v0.0.246...v0.0.249)
2023-02-21 10:57:28 +01:00
Hugo Osvaldo Barrera
2138c43456 Update docs for Google storages
References: https://github.com/pimutils/vdirsyncer/pull/985
References: https://github.com/pimutils/vdirsyncer/issues/975
Closes: https://github.com/pimutils/vdirsyncer/issues/1028
Closes: https://github.com/pimutils/vdirsyncer/issues/808
2023-02-16 23:17:27 +01:00
Hugo Osvaldo Barrera
5a46c93987 mypy: Drop unnecessary rule exclusion 2023-02-16 16:51:12 +01:00
Hugo Osvaldo Barrera
180f91f0fe Move mypy config to pyproject.toml 2023-02-16 16:51:12 +01:00
Hugo Osvaldo Barrera
6443d37c97 Move pytest config to pyproject.toml 2023-02-16 16:51:12 +01:00
pre-commit-ci[bot]
13ca008380 [pre-commit.ci] pre-commit autoupdate
updates:
- [github.com/pre-commit/mirrors-mypy: v0.991 → v1.0.0](https://github.com/pre-commit/mirrors-mypy/compare/v0.991...v1.0.0)
- [github.com/charliermarsh/ruff-pre-commit: v0.0.243 → v0.0.246](https://github.com/charliermarsh/ruff-pre-commit/compare/v0.0.243...v0.0.246)
2023-02-14 10:09:36 +01:00
Hugo Osvaldo Barrera
24cb49f64c Remove superfluous exception parens 2023-02-10 16:57:39 +01:00
Hugo Osvaldo Barrera
defe8e2591 Fix broken BSD link
pkgsrc.se is no more.
2023-02-10 16:54:08 +01:00
pre-commit-ci[bot]
e11fa357ff [pre-commit.ci] auto fixes from pre-commit.com hooks
for more information, see https://pre-commit.ci
2023-02-07 12:21:17 +01:00
pre-commit-ci[bot]
e20a65793e [pre-commit.ci] pre-commit autoupdate
updates:
- [github.com/psf/black: 22.12.0 → 23.1.0](https://github.com/psf/black/compare/22.12.0...23.1.0)
- [github.com/charliermarsh/ruff-pre-commit: v0.0.238 → v0.0.243](https://github.com/charliermarsh/ruff-pre-commit/compare/v0.0.238...v0.0.243)
2023-02-07 12:21:17 +01:00
pre-commit-ci[bot]
df14865f43 [pre-commit.ci] pre-commit autoupdate
updates:
- [github.com/psf/black: 22.10.0 → 22.12.0](https://github.com/psf/black/compare/22.10.0...22.12.0)
- [github.com/charliermarsh/ruff-pre-commit: v0.0.237 → v0.0.238](https://github.com/charliermarsh/ruff-pre-commit/compare/v0.0.237...v0.0.238)
2023-01-31 10:09:31 +01:00
Hugo Osvaldo Barrera
f45ecf6ad0 Simplify management of documentation dependencies 2023-01-31 01:11:24 +01:00
Hugo Osvaldo Barrera
72bcef282d Remove another unnecessary wrapper 2023-01-31 01:11:24 +01:00
Hugo Osvaldo Barrera
3a56f26d05 Drop unnecessary wrapping 2023-01-31 01:11:24 +01:00
Hugo Osvaldo Barrera
4dd17c7f59 This make target is gone; use pytest directly 2023-01-31 01:11:04 +01:00
Hugo Osvaldo Barrera
73f2554932 Check typos via pre-commit
So this runs more often (and also in CI).
2023-01-31 01:11:04 +01:00
Hugo Osvaldo Barrera
627f574777 Remove unnecessary param 2023-01-31 01:11:04 +01:00
Hugo Osvaldo Barrera
37a7f9bea8 This test is not async 2023-01-31 00:21:04 +01:00
Hugo Osvaldo Barrera
d2d1532883 Remove indirection 2023-01-31 00:21:04 +01:00
Hugo Osvaldo Barrera
0dcef26b9d Update build jobs with more descriptive names 2023-01-31 00:21:04 +01:00
Hugo Osvaldo Barrera
d646357cd3 Use ruff for code checking and linting
`isort` is failing in pre-commit.ci right now, so this might be good
timing.

See: https://whynothugo.nl/journal/2023/01/20/notes-on-ruff/
2023-01-31 00:19:14 +01:00
Hugo Osvaldo Barrera
8c6c0be15a This mutation of the control variable is intended 2023-01-31 00:19:14 +01:00
Hugo Osvaldo Barrera
dfc29db312 Use dict literal instead of dict() call 2023-01-31 00:19:14 +01:00
Hugo Osvaldo Barrera
a41cf64b6c Update ArchLinux CI setup 2023-01-31 00:19:14 +01:00
Hugo Osvaldo Barrera
a2eda52b71 Hottub expect DOS-style extensions 2023-01-31 00:19:14 +01:00
Hugo Osvaldo Barrera
61006f0685 Improve installation documentation
`pipx` is a lot simpler on any setup where this it is available.
2023-01-26 18:53:19 +01:00
Hugo Osvaldo Barrera
9b48bccde2 Fix return type
Fixes: https://github.com/pimutils/vdirsyncer/issues/1036
2023-01-26 18:01:08 +01:00
Hugo Osvaldo Barrera
7c72caef3f docs: We're not using aiohttp, not requests 2023-01-26 10:43:46 +01:00
Hugo Osvaldo Barrera
0045b23800 Add missing changelog entry
See: https://github.com/pimutils/vdirsyncer/pull/1031
2023-01-13 16:37:32 +01:00
Hugo Osvaldo Barrera
c07fbc2053 Add missing changelog entry
See: https://github.com/pimutils/vdirsyncer/pull/1016
2023-01-13 16:36:45 +01:00
Daniele Ricci
e3485beb45 Enable environment variables for HTTP proxy 2023-01-13 16:36:36 +01:00
Tonus
0f83fd96d5 Add Slackware as build-able version
I maintain the build script for Slackware on the slackbuilds.org repo (endorsed by Slackware).
2023-01-07 01:39:12 +01:00
chrysle
8980a80560 Corrected installation steps for Ubuntu and pip 2023-01-06 14:50:27 +01:00
pre-commit-ci[bot]
90b6ce1d04 [pre-commit.ci] pre-commit autoupdate
updates:
- [github.com/asottile/pyupgrade: v3.2.2 → v3.3.0](https://github.com/asottile/pyupgrade/compare/v3.2.2...v3.3.0)
2022-12-09 12:01:43 +01:00
waclaw66
7a801d3d5d Google Contacts discover fix 2022-12-09 12:00:52 +01:00
Hugo Osvaldo Barrera
2c44f7d773 Update flake8 comments to "new" format 2022-12-03 16:25:08 +01:00
Hugo Osvaldo Barrera
6506c86f58 Remove obsolete config value
This was used by flake8-import-order
2022-12-03 16:25:08 +01:00
pre-commit-ci[bot]
51b409017d [pre-commit.ci] pre-commit autoupdate
updates:
- [github.com/pre-commit/pre-commit-hooks: v4.3.0 → v4.4.0](https://github.com/pre-commit/pre-commit-hooks/compare/v4.3.0...v4.4.0)
- [github.com/PyCQA/flake8: 5.0.4 → 6.0.0](https://github.com/PyCQA/flake8/compare/5.0.4...6.0.0)
- [github.com/pre-commit/mirrors-mypy: v0.990 → v0.991](https://github.com/pre-commit/mirrors-mypy/compare/v0.990...v0.991)
2022-12-03 16:25:08 +01:00
Hugo Osvaldo Barrera
84613e73b0 Split out publishing for usual CI job
This separate one is to be triggered manually for tags.

Keep it simple.
2022-11-20 15:30:21 +01:00
Hugo Osvaldo Barrera
a4ef45095e Tidy up changelog for v0.19.beta1 2022-11-19 15:25:03 +01:00
Hugo Osvaldo Barrera
63ba948241 Fix mistaken return type
This return value is not used anywhere (clearly).
2022-11-19 15:17:11 +01:00
pre-commit-ci[bot]
3067b32de5 [pre-commit.ci] pre-commit autoupdate
updates:
- [github.com/psf/black: 22.6.0 → 22.10.0](https://github.com/psf/black/compare/22.6.0...22.10.0)
- [github.com/asottile/pyupgrade: v2.37.3 → v3.2.2](https://github.com/asottile/pyupgrade/compare/v2.37.3...v3.2.2)
- [github.com/pre-commit/mirrors-mypy: v0.971 → v0.990](https://github.com/pre-commit/mirrors-mypy/compare/v0.971...v0.990)
2022-11-19 15:17:11 +01:00
Hugo Osvaldo Barrera
a87518c474 Fix weird string formatting 2022-11-07 17:21:51 +01:00
Hugo Osvaldo Barrera
b26e771865 Fix bad syntax for adding finalizers 2022-11-07 17:21:10 +01:00
Hugo Osvaldo Barrera
2fbb0ab7a5 Clean up some invalid TLS configuration branches 2022-09-20 23:01:50 +02:00
Hugo Osvaldo Barrera
60352f84fe Untangle auth handling
This was a bit entangled and messed up due to recent changes.
2022-09-20 23:01:50 +02:00
Hugo Osvaldo Barrera
b7201013bc Remove duplicate command 2022-09-20 23:01:50 +02:00
Hugo Osvaldo Barrera
b61095ad47 Async fixtures must be marked as such
pytest_asyncio now uses strict mode by default.
2022-09-20 23:01:47 +02:00
pre-commit-ci[bot]
278e6de8b0 [pre-commit.ci] pre-commit autoupdate
updates:
- [github.com/PyCQA/flake8: 4.0.1 → 5.0.4](https://github.com/PyCQA/flake8/compare/4.0.1...5.0.4)
- [github.com/asottile/pyupgrade: v2.34.0 → v2.37.3](https://github.com/asottile/pyupgrade/compare/v2.34.0...v2.37.3)
- [github.com/pre-commit/mirrors-mypy: v0.961 → v0.971](https://github.com/pre-commit/mirrors-mypy/compare/v0.961...v0.971)
2022-08-09 21:11:42 +02:00
Hugo Osvaldo Barrera
843c58b92e Ignore flake8-bugbear false positive
See: https://github.com/PyCQA/flake8-bugbear/issues/269
2022-08-09 21:10:17 +02:00
Hugo Osvaldo Barrera
cd412aa161 Rename master branch to main 2022-08-05 17:07:33 +02:00
rEnr3n
c5f80d1644
Make systemd service restart only once on failure
Fixes https://github.com/pimutils/vdirsyncer/issues/998
2022-08-05 21:28:54 +08:00
Hugo
c50eabc77e
Merge pull request #995 from pimutils/pre-commit-ci-update-config
[pre-commit.ci] pre-commit autoupdate
2022-07-05 09:04:08 +00:00
pre-commit-ci[bot]
a88389c4f1
[pre-commit.ci] pre-commit autoupdate
updates:
- [github.com/psf/black: 22.3.0 → 22.6.0](https://github.com/psf/black/compare/22.3.0...22.6.0)
2022-07-04 22:14:46 +00:00
Hugo
1f7497c9d1
Merge pull request #985 from telotortium/gcal-oauth-remove-oob
gcal: replace oob OAuth2 with local server redirect
2022-06-26 18:42:37 +00:00
robert.irelan
baaf737873 gcal: replace oob OAuth2 with local server redirect
Google Calendar has disabled the oob method for new credentials (see
https://developers.google.com/identity/protocols/oauth2/native-app), so
new users cannot currently use Google Calendar. Fix this by switching to
a loopback redirect_uri flow instead.

Co-authored-by: Hugo Osvaldo Barrera <hugo@whynothugo.nl>
2022-06-26 19:40:35 +02:00
Hugo Osvaldo Barrera
7c2fed1ceb Update homebrew references
Also, it's called "macOS" nowadays.
2022-06-21 14:16:41 +02:00
Hugo Osvaldo Barrera
3be048be18 Drop macOS plist
This file is now generated by homebrew for mac users. As we have no
macOS devices to maintain our own, we'll just rely on their
implementation.

See: dfd51bebed/Formula/vdirsyncer.rb (L87-L94)
See: https://github.com/pimutils/vdirsyncer/pull/978
2022-06-21 14:16:41 +02:00
pre-commit-ci[bot]
f103b10b2a [pre-commit.ci] pre-commit autoupdate
updates:
- [github.com/pre-commit/pre-commit-hooks: v4.2.0 → v4.3.0](https://github.com/pre-commit/pre-commit-hooks/compare/v4.2.0...v4.3.0)
- [github.com/asottile/pyupgrade: v2.32.1 → v2.34.0](https://github.com/asottile/pyupgrade/compare/v2.32.1...v2.34.0)
- [github.com/pre-commit/mirrors-mypy: v0.960 → v0.961](https://github.com/pre-commit/mirrors-mypy/compare/v0.960...v0.961)
2022-06-14 09:54:00 +02:00
Hugo
e44c704ae3
Merge pull request #987 from pimutils/pre-commit-ci-update-config
[pre-commit.ci] pre-commit autoupdate
2022-05-30 22:58:36 +02:00
pre-commit-ci[bot]
f32e0a9c1f
[pre-commit.ci] pre-commit autoupdate
updates:
- [github.com/pre-commit/mirrors-mypy: v0.950 → v0.960](https://github.com/pre-commit/mirrors-mypy/compare/v0.950...v0.960)
2022-05-30 20:43:36 +00:00
Hugo
24e3625cc0
Merge pull request #982 from pimutils/pre-commit-ci-update-config
[pre-commit.ci] pre-commit autoupdate
2022-05-09 23:05:26 +02:00
pre-commit-ci[bot]
4df54b9231
[pre-commit.ci] pre-commit autoupdate
updates:
- [github.com/asottile/pyupgrade: v2.32.0 → v2.32.1](https://github.com/asottile/pyupgrade/compare/v2.32.0...v2.32.1)
2022-05-09 20:38:13 +00:00
Hugo
8557c6e0bb
Merge pull request #981 from pimutils/pre-commit-ci-update-config
[pre-commit.ci] pre-commit autoupdate
2022-05-02 23:06:13 +02:00
pre-commit-ci[bot]
9fdc93c140
[pre-commit.ci] pre-commit autoupdate
updates:
- [github.com/pre-commit/mirrors-mypy: v0.942 → v0.950](https://github.com/pre-commit/mirrors-mypy/compare/v0.942...v0.950)
2022-05-02 20:29:45 +00:00
Hugo
f3f8eb6824
Merge pull request #976 from pimutils/pre-commit-ci-update-config
[pre-commit.ci] pre-commit autoupdate
2022-04-12 12:06:26 +02:00
pre-commit-ci[bot]
b18e1c78d2 Auto fixes from pre-commit hooks 2022-04-12 00:03:51 +02:00
pre-commit-ci[bot]
0a4114ef9f
[pre-commit.ci] pre-commit autoupdate
updates:
- [github.com/pre-commit/pre-commit-hooks: v4.1.0 → v4.2.0](https://github.com/pre-commit/pre-commit-hooks/compare/v4.1.0...v4.2.0)
- [github.com/asottile/pyupgrade: v2.31.1 → v2.32.0](https://github.com/asottile/pyupgrade/compare/v2.31.1...v2.32.0)
2022-04-11 21:09:08 +00:00
Hugo
06f8001d65
Merge pull request #974 from pimutils/pre-commit-ci-update-config
[pre-commit.ci] pre-commit autoupdate
2022-04-05 09:36:21 +02:00
pre-commit-ci[bot]
61f3785e6c
[pre-commit.ci] pre-commit autoupdate
updates:
- [github.com/psf/black: 22.1.0 → 22.3.0](https://github.com/psf/black/compare/22.1.0...22.3.0)
2022-04-04 20:08:40 +00:00
Hugo
b0020f9436
Merge pull request #973 from pimutils/pre-commit-ci-update-config
[pre-commit.ci] pre-commit autoupdate
2022-03-28 21:40:48 +02:00
pre-commit-ci[bot]
74d738ec80
[pre-commit.ci] pre-commit autoupdate
updates:
- [github.com/pre-commit/mirrors-mypy: v0.941 → v0.942](https://github.com/pre-commit/mirrors-mypy/compare/v0.941...v0.942)
2022-03-28 19:22:10 +00:00
Hugo
711eccedab
Merge pull request #972 from pimutils/pre-commit-ci-update-config
[pre-commit.ci] pre-commit autoupdate
2022-03-22 13:24:40 +01:00
Hugo Osvaldo Barrera
5d58a86ba0 Avoid shadowing iterable inside for loop 2022-03-22 08:27:08 +01:00
pre-commit-ci[bot]
60c3b59552 [pre-commit.ci] auto fixes from pre-commit.com hooks
for more information, see https://pre-commit.ci
2022-03-21 22:41:54 +00:00
pre-commit-ci[bot]
22a127191d
[pre-commit.ci] pre-commit autoupdate
updates:
- [github.com/psf/black: 21.12b0 → 22.1.0](https://github.com/psf/black/compare/21.12b0...22.1.0)
- [github.com/asottile/pyupgrade: v2.31.0 → v2.31.1](https://github.com/asottile/pyupgrade/compare/v2.31.0...v2.31.1)
- [github.com/pre-commit/mirrors-mypy: v0.931 → v0.941](https://github.com/pre-commit/mirrors-mypy/compare/v0.931...v0.941)
2022-03-21 22:41:09 +00:00
Hugo
dc6e4ba5af
Merge pull request #971 from pimutils/update-click-log
Support click-log 0.4.0
2022-03-15 19:55:58 +01:00
Hugo Osvaldo Barrera
ea640001d0 Support click-log 0.4.0 2022-03-14 16:25:54 +01:00
Hugo Osvaldo Barrera
545b8ce2f1 token_updater needs to be an async function 2022-02-06 00:55:31 +01:00
Hugo Osvaldo Barrera
3035d9cfae Add some extra type hints 2022-02-06 00:55:17 +01:00
Hugo Osvaldo Barrera
68c5968be8 Tidy up spacing in donations page 2022-01-16 05:03:52 +01:00
Hugo Osvaldo Barrera
0d1ca319c0
Merge pull request #962 from pimutils/donations
Update donations links
2022-01-16 05:02:44 +01:00
Hugo Osvaldo Barrera
817eab51f1
Update donations links
Signed-off-by: Hugo Osvaldo Barrera <hugo@barrera.io>
2022-01-15 20:15:05 +01:00
Hugo Osvaldo Barrera
e8b72130c2
Merge pull request #961 from dilyanpalauzov/readonly_metadata
vdirsyncer/metasync.py: for read_only storages adjust the metadata resolution in favour of the read_only storage
2022-01-14 16:39:23 +01:00
Дилян Палаузов
8a44b278d1 vdirsyncer/metasync.py: for read_only storages adjust the metadata resolution in favour of the read_only storage 2022-01-14 13:52:04 +02:00
Hugo Osvaldo Barrera
54a5bf4ad3
Merge pull request #953 from electrickite/shell-fetch
Add shell strategy to fetch params
2022-01-14 12:48:07 +01:00
Hugo Osvaldo Barrera
10659b80ba
Merge pull request #960 from dilyanpalauzov/readonly_metadata
storage/base: for read_only storages do not overwrite the meta data
2022-01-14 12:47:18 +01:00
Дилян Палаузов
1c6beae9b4 storage/base: for read_only storages do not overwrite the meta data 2022-01-14 13:10:49 +02:00
Hugo Osvaldo Barrera
7ce9466c46
Merge pull request #959 from pimutils/pre-commit-ci-update-config
[pre-commit.ci] pre-commit autoupdate
2022-01-10 22:31:17 +01:00
pre-commit-ci[bot]
9f0390ee21
[pre-commit.ci] pre-commit autoupdate
updates:
- [github.com/pre-commit/mirrors-mypy: v0.930 → v0.931](https://github.com/pre-commit/mirrors-mypy/compare/v0.930...v0.931)
2022-01-10 20:32:13 +00:00
Hugo Osvaldo Barrera
4e3f39468b
Merge pull request #958 from pimutils/pre-commit-ci-update-config
[pre-commit.ci] pre-commit autoupdate
2022-01-04 16:03:08 +01:00
pre-commit-ci[bot]
a7e984f013
[pre-commit.ci] pre-commit autoupdate
updates:
- [github.com/asottile/pyupgrade: v2.29.1 → v2.31.0](https://github.com/asottile/pyupgrade/compare/v2.29.1...v2.31.0)
2022-01-03 20:09:57 +00:00
Hugo Osvaldo Barrera
7c7f97c6b2
Merge pull request #956 from pimutils/pre-commit-ci-update-config
[pre-commit.ci] pre-commit autoupdate
2021-12-27 22:30:22 +01:00
pre-commit-ci[bot]
7e9132b817
[pre-commit.ci] pre-commit autoupdate
updates:
- [github.com/pre-commit/pre-commit-hooks: v4.0.1 → v4.1.0](https://github.com/pre-commit/pre-commit-hooks/compare/v4.0.1...v4.1.0)
- [github.com/pre-commit/mirrors-mypy: v0.910-1 → v0.930](https://github.com/pre-commit/mirrors-mypy/compare/v0.910-1...v0.930)
2021-12-27 20:15:19 +00:00
pre-commit-ci[bot]
59b95d9999 [pre-commit.ci] auto fixes from pre-commit.com hooks
for more information, see https://pre-commit.ci
2021-12-09 16:18:10 +00:00
Corey Hinshaw
4dd15716db Adds shell strategy to config fetch params to run command string in a shell 2021-12-09 11:17:43 -05:00
Hugo Osvaldo Barrera
ec101b20d6
Merge pull request #947 from pimutils/pre-commit-ci-update-config
[pre-commit.ci] pre-commit autoupdate
2021-12-06 21:11:35 +00:00
pre-commit-ci[bot]
2c551afafb [pre-commit.ci] auto fixes from pre-commit.com hooks
for more information, see https://pre-commit.ci
2021-12-06 20:14:52 +00:00
pre-commit-ci[bot]
ad7bb82f40
[pre-commit.ci] pre-commit autoupdate
updates:
- [github.com/psf/black: 21.9b0 → 21.12b0](https://github.com/psf/black/compare/21.9b0...21.12b0)
- [github.com/pycqa/isort: 5.9.3 → 5.10.1](https://github.com/pycqa/isort/compare/5.9.3...5.10.1)
- [github.com/asottile/pyupgrade: v2.29.0 → v2.29.1](https://github.com/asottile/pyupgrade/compare/v2.29.0...v2.29.1)
2021-12-06 20:13:26 +00:00
Hugo Osvaldo Barrera
961203e865 Require aiohttp >= 3.8.0
See https://github.com/pimutils/vdirsyncer/issues/916#issuecomment-957671206
See https://github.com/aio-libs/aiohttp/issues/5156
2021-11-02 18:07:13 +01:00
Hugo Osvaldo Barrera
d72536805c
Merge pull request #943 from pimutils/deb
Update script to publish deb packages
2021-10-22 20:15:05 +02:00
Hugo Osvaldo Barrera
ac6e19261f
Merge pull request #944 from pimutils/pre-commit-ci-update-config
[pre-commit.ci] pre-commit autoupdate
2021-10-11 23:29:08 +02:00
pre-commit-ci[bot]
cbb0cad827
[pre-commit.ci] pre-commit autoupdate
updates:
- [github.com/PyCQA/flake8: 3.9.2 → 4.0.1](https://github.com/PyCQA/flake8/compare/3.9.2...4.0.1)
- [github.com/pre-commit/mirrors-mypy: v0.910 → v0.910-1](https://github.com/pre-commit/mirrors-mypy/compare/v0.910...v0.910-1)
2021-10-11 19:00:13 +00:00
Hugo Osvaldo Barrera
2c69f865f0 Update script to publish deb packages
Creating a docker image and then running inside of it was a bit complex,
and tricky to debug when things needed maintenance.

Just use a debian/ubuntu container, but run our script inside of it.
Manually debugging is much easier, and the whole setup is a bit simpler.
2021-10-06 00:48:25 +02:00
Hugo Osvaldo Barrera
63510414ae
Merge pull request #941 from pimutils/pre-commit-ci-update-config
[pre-commit.ci] pre-commit autoupdate
2021-10-05 22:38:00 +02:00
Hugo Osvaldo Barrera
fce5062a12
Merge pull request #942 from pimutils/drop-etesync
Drop etesync
2021-10-05 22:26:35 +02:00
Hugo Osvaldo Barrera
c77d750ef6 Drop etesync
The current [experimental] implementation is stale, and hasn't been
maintained for a long time. Regrettably, not even its tests still work,
and there nobody interested in maintaining it.

If anyone is interested in re-implementing this in a third-party
package, I can consider adding support for pluggable storages.
2021-10-05 22:13:59 +02:00
pre-commit-ci[bot]
02ee9f96e4
[pre-commit.ci] pre-commit autoupdate
updates:
- [github.com/asottile/pyupgrade: v2.28.0 → v2.29.0](https://github.com/asottile/pyupgrade/compare/v2.28.0...v2.29.0)
2021-10-04 19:00:20 +00:00
Hugo Osvaldo Barrera
ddaeccb2ee
Merge pull request #940 from pimutils/pre-commit-ci-update-config
[pre-commit.ci] pre-commit autoupdate
2021-09-27 22:00:46 +02:00
pre-commit-ci[bot]
63ef204835 [pre-commit.ci] auto fixes from pre-commit.com hooks
for more information, see https://pre-commit.ci
2021-09-27 18:57:05 +00:00
pre-commit-ci[bot]
7d61cd3e2e
[pre-commit.ci] pre-commit autoupdate
updates:
- [github.com/asottile/pyupgrade: v2.26.0 → v2.28.0](https://github.com/asottile/pyupgrade/compare/v2.26.0...v2.28.0)
2021-09-27 18:56:47 +00:00
Hugo Osvaldo Barrera
db6da70c26
Merge pull request #939 from pimutils/pre-commit-ci-update-config
[pre-commit.ci] pre-commit autoupdate
2021-09-22 21:02:10 +02:00
pre-commit-ci[bot]
bf95bf2941
[pre-commit.ci] pre-commit autoupdate
updates:
- [github.com/psf/black: 21.8b0 → 21.9b0](https://github.com/psf/black/compare/21.8b0...21.9b0)
2021-09-20 19:07:52 +00:00
Hugo Osvaldo Barrera
b3c9df1b1d
Merge pull request #937 from pimutils/pre-commit-ci-update-config
[pre-commit.ci] pre-commit autoupdate
2021-09-13 21:42:01 +02:00
Hugo Osvaldo Barrera
87574be547 Stop running pre-commit twice 2021-09-13 21:27:11 +02:00
Hugo Osvaldo Barrera
2e35214421 Remove unused import 2021-09-13 21:27:06 +02:00
pre-commit-ci[bot]
f5c2026dcf [pre-commit.ci] auto fixes from pre-commit.com hooks
for more information, see https://pre-commit.ci
2021-09-13 18:57:16 +00:00
pre-commit-ci[bot]
acf29cf659
[pre-commit.ci] pre-commit autoupdate
updates:
- [github.com/asottile/pyupgrade: v2.25.0 → v2.26.0](https://github.com/asottile/pyupgrade/compare/v2.25.0...v2.26.0)
2021-09-13 18:56:33 +00:00
Hugo Osvaldo Barrera
fbd5ff88d5
Merge pull request #935 from pimutils/pre-commit-ci-update-config
[pre-commit.ci] pre-commit autoupdate
2021-08-30 22:23:53 +02:00
pre-commit-ci[bot]
7605416054
[pre-commit.ci] pre-commit autoupdate
updates:
- [github.com/psf/black: 21.7b0 → 21.8b0](https://github.com/psf/black/compare/21.7b0...21.8b0)
- [github.com/asottile/pyupgrade: v2.24.0 → v2.25.0](https://github.com/asottile/pyupgrade/compare/v2.24.0...v2.25.0)
2021-08-30 18:41:20 +00:00
Hugo Osvaldo Barrera
7a12e6028c
Merge pull request #933 from pimutils/pre-commit-ci-update-config
[pre-commit.ci] pre-commit autoupdate
2021-08-23 20:39:58 +02:00
pre-commit-ci[bot]
d6876c6bad
[pre-commit.ci] pre-commit autoupdate
updates:
- [github.com/asottile/pyupgrade: v2.23.3 → v2.24.0](https://github.com/asottile/pyupgrade/compare/v2.23.3...v2.24.0)
2021-08-23 18:16:49 +00:00
Hugo Osvaldo Barrera
09eb375c5b
Merge pull request #929 from pimutils/fix-918
Fix 918
2021-08-21 15:39:05 +02:00
Hugo Osvaldo Barrera
48747463ed Remove unused code 2021-08-19 20:40:47 +02:00
Hugo Osvaldo Barrera
955f434d9d Also test syncing with an href with a colon
Since this was the actual problematic character.
2021-08-18 18:41:00 +02:00
Hugo Osvaldo Barrera
889183ec89 I think this makes sense 2021-08-18 18:20:04 +02:00
Hugo Osvaldo Barrera
0650cc3bc2 Add test for #918
We're doing something wrong with UID/href quoting/unquoting, but I've
yet to figure out what.
2021-08-18 18:20:04 +02:00
Hugo Osvaldo Barrera
6281e7a237 Radicale now passes for this test 2021-08-18 18:20:04 +02:00
Hugo Osvaldo Barrera
dff48f101b
Merge pull request #928 from pimutils/fastmail-recurrence-sorting
Work around quirk in Fastmail
2021-08-18 18:19:35 +02:00
Hugo Osvaldo Barrera
1081a15895 Work around quirk in Fastmail
They seem to sort the parameters in an RRULE in a specific order, so
just use that by default to avoid any mismatch.
2021-08-16 22:29:16 +02:00
Hugo Osvaldo Barrera
cf1d082628 Use context managers for aio connectors
Not sure why we didn't do this initially, but this ensures that we
always close all connectors properly, and also gives much clearer scope
regarding their life-cycles.
2021-08-16 21:40:11 +02:00
Hugo Osvaldo Barrera
54e829262d
Merge pull request #926 from pimutils/python37-tests
Run tests CI python 3.7
2021-08-07 23:29:13 +02:00
Hugo Osvaldo Barrera
8830307e38 Drop syntax that won't run on Python 3.7 2021-08-07 17:26:01 +02:00
Hugo Osvaldo Barrera
7a7deffa2c Run test on Python 3.7
Run these on a synthetic environment, since no distribution seems to
currently ship this version.
2021-08-07 17:23:10 +02:00
Hugo Osvaldo Barrera
ecb181d9d7
Merge pull request #925 from pimutils/pyupgrade
Set up pyupgrade
2021-08-04 20:43:50 +02:00
Hugo Osvaldo Barrera
fed1ee69c3 Run pyupgrade 2021-08-04 19:58:59 +02:00
Hugo Osvaldo Barrera
48aa4912a2 Add pyupgrade as a pre-commit hook 2021-08-04 19:58:31 +02:00
Hugo Osvaldo Barrera
8886854367
Merge pull request #912 from pimutils/typing
Add some typing hints
2021-08-04 15:12:35 +02:00
Hugo Osvaldo Barrera
a910e9f446 Stop marking wheels as universal
We don't support Python 2, so they're not universal.
2021-08-04 00:18:22 +02:00
Hugo Osvaldo Barrera
f3714fc493 Add type hints and configure mypy
Configure mypy as a pre-commit hook and add all type hints necessary for
mypy to pass.

There's still more work to be done here typing a lot more code, but this
provides a clear starting point.
2021-08-03 19:23:37 +02:00
Hugo Osvaldo Barrera
6af4dd124b
Merge pull request #924 from pimutils/pre-commit-ci-update-config
[pre-commit.ci] pre-commit autoupdate
2021-08-02 22:09:04 +02:00
pre-commit-ci[bot]
bc5e03630e
[pre-commit.ci] pre-commit autoupdate
updates:
- [github.com/pycqa/isort: 5.9.2 → 5.9.3](https://github.com/pycqa/isort/compare/5.9.2...5.9.3)
2021-08-02 18:06:08 +00:00
Hugo Osvaldo Barrera
6491bc53fb
Merge pull request #923 from pimutils/pre-commit-ci-update-config
[pre-commit.ci] pre-commit autoupdate
2021-07-27 18:26:21 +02:00
pre-commit-ci[bot]
21eccfc2ef
[pre-commit.ci] pre-commit autoupdate
updates:
- https://gitlab.com/pycqa/flake8https://github.com/PyCQA/flake8
- [github.com/psf/black: 21.6b0 → 21.7b0](https://github.com/psf/black/compare/21.6b0...21.7b0)
- [github.com/pycqa/isort: 5.8.0 → 5.9.2](https://github.com/pycqa/isort/compare/5.8.0...5.9.2)
2021-07-26 17:54:50 +00:00
Hugo Osvaldo Barrera
7b493416f7
Merge pull request #920 from pimutils/meta_delete
metasync: use None as no-value and delete missing values on syncing
2021-07-26 13:07:45 +02:00
Hugo Osvaldo Barrera
5b8f00e720 Sort imports 2021-07-25 18:35:47 +02:00
Hugo Osvaldo Barrera
0556e53e0c Use isort to reorder python imports
reorder-python-imports is hard to set up correctly.

isort is a lot simpler to set to set up it locally, and is kinda
becoming the standard in the python world.

The import style remains the same, and is tweaked to minimise conflicts.
2021-07-25 18:35:04 +02:00
Hugo Osvaldo Barrera
7379a96f73 Skip test on unsupported servers 2021-07-23 20:27:34 +02:00
Дилян Палаузов
c0ccb3d1aa metasync: use None as no-value and delete missing values on syncing
- change the interface of Storage.get_meta() and .set_meta()
  to use '' as the empty value and None as missing value.

- When a property is missing (e.g calendar-color was removed)
  in the filesystem storage delete the 'color' file, and
  in the WebDAV storage issue propertyupdate/remove call.

- remove the property from [status]/[pair]/[collection].metadata

I have adjusted, but not run the test suite.  On the other side
I tested on real system: source is CalDAV - destination is filesystem;
and source is CalDAV, destination is CalDAV (another account)
2021-07-23 19:07:02 +02:00
Hugo Osvaldo Barrera
98fcd12fa7 Only measure coverage of vdirsyncer/
i.e.: Ignore non-application code like  contrib/
2021-07-10 17:35:50 +02:00
Hugo Osvaldo Barrera
f2a1afe6d3
Merge pull request #915 from pimutils/formatting
Make command bit more readable
2021-07-10 17:33:34 +02:00
Hugo Osvaldo Barrera
e16f83c1c2 Make this bit more readable 2021-07-07 18:46:13 +02:00
Hugo Osvaldo Barrera
55c563ff8c
Merge pull request #893 from Intevation/conflict-resolution-interactive
Add contrib script to resolve conflicts
2021-07-07 18:41:54 +02:00
Hugo Osvaldo Barrera
a5731b269e
Merge pull request #913 from pimutils/async-collections
Sync pairs asynchronously
2021-07-07 18:21:06 +02:00
Hugo Osvaldo Barrera
459efbf7af
Merge pull request #914 from pimutils/simpler-coverage
Simplify coverage submission
2021-07-07 15:10:10 +02:00
Hugo Osvaldo Barrera
58aa0a3a31 Simplify coverage submission
We submit separate coverage reports for each group of tests, but codecov
doesn't give us proper tooling to analyse each one separately. When
there's a percentage drop in one, there's no way to pinpoint where -- at
least not without running locally and inspecting results separately.

Treat all coverage as one. Analysis of coverage for each group of tests
can be done offline and manually, but there's little value in keeping it
in codecov.

Should also help us transition a more simplified CI design (e.g.:
running all tests together rather than in groups).
2021-07-06 23:45:35 +02:00
Hugo Osvaldo Barrera
177748d3d1 Sync pairs asynchronously 2021-07-06 23:13:13 +02:00
Bernhard Reiter
61edfc090e
Adjust codestyle
running flake8, black and reorder-python-imports.
2021-06-28 16:01:21 +02:00
Bernhard Reiter
b3bee77c17
Change license from Apache-2.0 to BSD-3-Clause
to match the license of vdirsyncer
2021-06-28 15:22:56 +02:00
Hugo Osvaldo Barrera
21db2547cb
Merge pull request #911 from pimutils/optimise-test-servers
Minor optimisations to tests
2021-06-27 18:31:11 +02:00
Hugo Osvaldo Barrera
be131a0063
Merge pull request #910 from pimutils/orage
Update link for orage
2021-06-27 13:17:06 +02:00
Hugo Osvaldo Barrera
71879045e4 Tidy up test collection creation
- No need to empty collections, they're generated with a UUID and should
  always be empty (the code to empty them does not actually run in CI
  right now).
- Move deletion code to _after_ the yield, since that's the order in
  which things happen.
- Delete all collections asynchronously.
2021-06-27 13:16:31 +02:00
Hugo Osvaldo Barrera
54e0c114fa Update link for orage
The previous one is 404, and that domain redirects to some random
website.
2021-06-27 12:37:33 +02:00
Hugo Osvaldo Barrera
17f422c1b7 Auto-delete test containers 2021-06-26 19:59:56 +02:00
Hugo Osvaldo Barrera
a9f1a5195a Tweak output when running tests 2021-06-26 19:59:56 +02:00
Hugo Osvaldo Barrera
8dab258ef0
Merge pull request #909 from pimutils/fastmail
Run Fastmail on CI again
2021-06-26 18:40:50 +02:00
Hugo Osvaldo Barrera
f09d060580 Run Fastmail tests on CI 2021-06-26 18:25:35 +02:00
Hugo Osvaldo Barrera
ef2419efa9 Avoid running bogus tests with Fastmail
The fix that disabled VTODO tests accidentally ran all other tests twice
for this storage.

This wasn't picked up earlier since Fastmail is not currently running on
CI.
2021-06-26 18:12:54 +02:00
Hugo Osvaldo Barrera
2eff8e08e1 Fix breakage in Fastmail tests
Some code that wasn't updated with the switch to asyncio.
2021-06-26 18:12:22 +02:00
Hugo Osvaldo Barrera
152ebb05dd
Merge pull request #906 from pimutils/async
Initial asyncio support
2021-06-26 15:56:23 +02:00
Hugo Osvaldo Barrera
5a9fc2cc7e Add changelog entries for asyncio support 2021-06-26 13:40:38 +02:00
Hugo Osvaldo Barrera
dfed9794cb Port google storage to use asyncio 2021-06-26 13:40:38 +02:00
Hugo Osvaldo Barrera
8d69b73c9e Fetch displaynames asynchronously 2021-06-26 13:40:38 +02:00
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
Hugo Osvaldo Barrera
7c9170c677 Remove unecessary indirection 2021-06-26 13:02:41 +02:00
Hugo Osvaldo Barrera
623c0537e1 Update test 2021-06-26 13:02:41 +02:00
Hugo Osvaldo Barrera
4930b5f389 Drop multithreading support
This is mainly in preparation to moving to an async architecture.
2021-06-26 13:02:41 +02:00
Hugo Osvaldo Barrera
25435ce11d
Merge pull request #903 from pimutils/fix-old-ssl-tests
Fix SSL tests failing due to old weak MDs
2021-06-26 13:01:17 +02:00
Hugo Osvaldo Barrera
1f6cc6f8be Fix SSL tests failing due to old weak MDs
Had to drop pytest-localserver, since it's broken and upstream is gone.
2021-06-20 18:49:02 +02:00
Hugo Osvaldo Barrera
59b6e24795
Merge pull request #905 from pimutils/showconfig
Add a command to print the current config
2021-06-19 13:38:15 +02:00
Hugo Osvaldo Barrera
722dace828
Merge pull request #904 from pimutils/improve-error-msg
Fix double-use of a generator
2021-06-19 13:11:24 +02:00
Hugo Osvaldo Barrera
6cebba0853 Add a changelog entry 2021-06-17 08:42:45 +02:00
Hugo Osvaldo Barrera
29528123a3 Add a command to print the current config
This is intended to be used by external tools and integrations (such as
daemons which trigger `vdirsyncer` when there's a change in a
collection).
2021-06-16 19:03:50 +02:00
Hugo Osvaldo Barrera
72618e374d Fix double-use of a generation
The first use exhausted it, so the second iteration was empty.
2021-06-14 22:50:22 +02:00
Witcher01
c254b4ad1d fixed password.fetch option not using environment
the '_strategy_command' in 'fetchparams.cli' did not expand the path of
every argument, but only the first one (being the command to be
executed).
i fixed the '_strategy_command' function to apply the 'expand_path'
function to every member of the commands list.
2021-06-13 16:14:46 +02:00
Hugo Osvaldo Barrera
cfd5af832a Fix mixup in the changelog 2021-06-13 16:12:52 +02:00
Hugo Osvaldo Barrera
342cb863cd Merge remote-tracking branch 'dilyanpalauzov/meta_description' 2021-06-13 16:12:09 +02:00
Hugo Osvaldo Barrera
e1c979751d Remove legacy GitHub Action workflows
Conflicts with our newer pipeline when a tag is pushed.
2021-06-13 16:11:13 +02:00
Hugo Osvaldo Barrera
3191886658
Merge pull request #901 from pimutils/publish
Publish tags to PyPI
2021-06-13 15:49:37 +02:00
Hugo Osvaldo Barrera
3260afb495 Publish tags to PyPI 2021-06-13 14:20:28 +02:00
Hugo Osvaldo Barrera
0231f3999e order is probably less important than the others 2021-06-13 00:52:39 +02:00
Hugo Osvaldo Barrera
d1b148c919 Improve docs for new meta properties 2021-06-13 00:49:27 +02:00
Hugo Osvaldo Barrera
e70e8c03e8 Merge branch 'origin/master' into meta_description 2021-06-13 00:46:05 +02:00
Hugo Osvaldo Barrera
46a49e3481
Merge pull request #900 from pimutils/more-git-optimizations
Optimize another very slow test
2021-06-13 00:28:12 +02:00
Hugo Osvaldo Barrera
5e36ca1334 Optimize another very slow test 2021-06-12 23:49:23 +02:00
Hugo Osvaldo Barrera
910317d4bb
Merge pull request #899 from pimutils/faster-tests
Faster tests
2021-06-12 23:41:29 +02:00
Hugo Osvaldo Barrera
29c2b6bb4b git-ignore coverage file 2021-06-12 18:39:28 +02:00
Hugo Osvaldo Barrera
2e4fc7c65a Drop unecessary hypothesis usage
This adds A LOT of time to test execution, for little benefit. While
having random data is good, in reality, most of it was just numbers, and
we rarely got very diverse data.

These hand-picked samples are as good to catch any regressions or issues
with servers.
2021-06-12 18:32:05 +02:00
Hugo Osvaldo Barrera
87f3a594c6
Merge pull request #897 from pimutils/optimise-test-servers
Run test servers as fixtures
2021-06-12 17:13:31 +02:00
Hugo Osvaldo Barrera
d95a8264f4 Merge style dependencies into dev dependencies 2021-06-12 16:28:27 +02:00
Hugo Osvaldo Barrera
77d64ddc2c Always check link as part of building docs 2021-06-12 16:28:27 +02:00
Hugo Osvaldo Barrera
808e01f9c8 DAVDroid is now called DAVx⁵ 2021-06-12 16:28:27 +02:00
Hugo Osvaldo Barrera
86535a9db3 Merge test dependencies into dev dependencies 2021-06-12 16:28:27 +02:00
Hugo Osvaldo Barrera
57d662cba1 Drop make target for development packages
We no longer track compat with unreleased packages. Too many variations
and too much complexity.

`vdirsyncer` only works with released packages.
2021-06-12 16:28:27 +02:00
Hugo Osvaldo Barrera
8d62ac4279 Pin the maximum version of click
We're likely won't be compatible with 9.0.
2021-06-12 16:28:27 +02:00
Hugo Osvaldo Barrera
3bf4bd079d Tidy up CI build definitions 2021-06-12 16:28:27 +02:00
Hugo Osvaldo Barrera
39ccc168b2 Show a useful help message by default 2021-06-12 16:28:27 +02:00
Hugo Osvaldo Barrera
7b0d6671da Delete unused variable 2021-06-12 16:28:27 +02:00
Hugo Osvaldo Barrera
8e8c1d5719 Update docs on test DAV servers 2021-06-12 16:28:27 +02:00
Hugo Osvaldo Barrera
299c699cb9 Manage test DAV servers as fixtures
Rather than require manually starting them before tests, manage them as
fixtures an initialise/destroy them as needed.
2021-06-12 16:28:24 +02:00
Hugo Osvaldo Barrera
8cd4a44d02 Simplify definition of DAV_SERVERs 2021-06-12 15:01:08 +02:00
Hugo Osvaldo Barrera
b0f08e051a
Merge pull request #895 from pimutils/optimise-test-servers
Run CI storage tests against Baikal again
2021-06-12 14:21:50 +02:00
Hugo Osvaldo Barrera
4450393d4f Typo
Fixes #892
2021-06-12 13:27:47 +02:00
Hugo Osvaldo Barrera
6c80293a98 Mark failing baikal tests as xfail 2021-06-12 13:26:01 +02:00
Hugo Osvaldo Barrera
a9fa61040f Tidy up some collection initializations 2021-06-12 13:23:54 +02:00
Hugo Osvaldo Barrera
ee124f5c82 Improve readability of failed tests 2021-06-12 13:23:52 +02:00
Hugo Osvaldo Barrera
5a97307a2f Remove unecessary exclusion 2021-06-12 13:08:25 +02:00
Hugo Osvaldo Barrera
e467809bb0 Update pre-commit hooks 2021-06-12 13:08:04 +02:00
Hugo Osvaldo Barrera
320ac6020b Tweak linter to ignore less issues 2021-06-12 12:58:13 +02:00
Hugo Osvaldo Barrera
9d3ef030fa Remove pointless condition
These tasks are named "ci-*", no point in hiding them in other envs.
2021-06-12 12:41:30 +02:00
Hugo Osvaldo Barrera
eec142ac15 Drop mysteryshack support
It's been unmaintained for years, so no point in keeping track of
compatibility.
2021-06-12 12:06:07 +02:00
Hugo Osvaldo Barrera
96f1c41bee Run CI with Baikal too 2021-06-12 12:06:07 +02:00
Hugo Osvaldo Barrera
a0b814ec17 Add a bit of docs to build manifests 2021-06-12 12:06:07 +02:00
Hugo Osvaldo Barrera
91ffb931e1 Move baikal out-of-repo too 2021-06-12 12:06:07 +02:00
Hugo Osvaldo Barrera
bba9d43caf Remove empty install files 2021-06-12 12:06:03 +02:00
Hugo Osvaldo Barrera
ec221b52b4 Update docs with new images names 2021-06-12 12:05:00 +02:00
Hugo Osvaldo Barrera
2336076baf
Merge pull request #894 from pimutils/optimise-test-servers
Move test server dockerfiles out-of-repo
2021-06-12 11:36:15 +02:00
Hugo Osvaldo Barrera
d747977af2 Use externally-built containers for test servers
This speeds up CI by avoiding a rebuild of these container on each run.
2021-06-12 10:59:44 +02:00
Hugo Osvaldo Barrera
0e47775ce3 Remove unused submodules
These submodules were used to bootstrap local test servers for running
integration tests.

We'll be reusing that codebase inside docker containers, but don't want
the containers built for each push to this repo -- that'll happen in a
separate repository.
2021-06-12 10:59:44 +02:00
Hugo Osvaldo Barrera
d6c1b1847c Fix a few linting errors 2021-06-12 10:59:44 +02:00
Bernhard Reiter
95bf683771
Add contrib script to resolve conflicts
Asks the user when two iCalender objects conflict during a sync,
which one to take.
2021-06-11 16:50:00 +02:00
Hugo Osvaldo Barrera
5844480588
Merge pull request #889 from Intevation/dev-issue881
Implement more flexibility for storage/filesystem
2021-06-11 11:37:12 +02:00
Bernhard Reiter
b9f5d88af9
Fixing docs/config.rst and code formatting 2021-06-02 13:52:10 +02:00
Hugo Osvaldo Barrera
5c00cceeb4 Update changelog for 0.18.0 2021-05-31 08:32:18 +02:00
Hugo Barrera
5e3e57ffc2
Merge pull request #891 from pimutils/fix-master
Update click-threading to 0.5.0
2021-05-31 09:56:57 +02:00
Hugo Osvaldo Barrera
addab47786 Update click-threading to 0.5.0
Previous version broke with recent `click` updates.
2021-05-30 22:30:01 +02:00
Hugo Barrera
32bc8d9046
Merge pull request #890 from pimutils/irc
Replace Freenode with Libera.Chat
2021-05-26 17:20:23 +02:00
Hugo Osvaldo Barrera
0d0f2974ae Replace Freenode with Libera.Chat 2021-05-26 00:19:06 +02:00
Bernhard Reiter
9a1582cc0f
Improve storage/filesystem docs
add hints about how to use the `fileext` and `fileignoreext` parameters.
2021-05-21 14:22:30 +02:00
Bernhard Reiter
9b5e01ab38
Improve storage/test_filesystem
with one additional test and fixing of the documentation.
2021-05-20 12:50:05 +02:00
Bernhard Reiter
81895c291e
Make /storage/filesystem more flexible
by adding the optional fileignoreext parameter.
2021-05-19 18:00:09 +02:00
Bernhard Reiter
439e63f8ea
Make /storage/filesystem ignore .tmp files
Hardcode to ignore files with `.tmp` suffix as this is mentioned
in the vdir specification.
2021-05-19 17:51:57 +02:00
Bernhard Reiter
804b9f0429
Add tests to filesystem storage for file ignorance
that ignore .tmp files even when fileext is empty.
Prepares to make the filesystem storage more universal as part of #881 .
2021-05-19 17:40:04 +02:00
Hugo Barrera
44e4beb06f
Merge pull request #886 from pimutils/black
Black
2021-05-11 21:11:09 +02:00
Hugo Barrera
94f8d608ec
Merge pull request #885 from pimutils/deb
Update build script for Debian/Ubuntu
2021-05-11 20:31:42 +02:00
Hugo Osvaldo Barrera
d2d41e5df1 Use black to auto-format the codebase 2021-05-06 19:28:54 +02:00
Hugo Osvaldo Barrera
abf199f21e Fix using mutable object as default arg 2021-05-06 19:28:08 +02:00
Hugo Osvaldo Barrera
75719ecc66 Update pre-commit hooks 2021-05-06 19:26:30 +02:00
Hugo Osvaldo Barrera
9513ee7f61 Update build script for Debian/Ubuntu 2021-05-06 19:11:43 +02:00
Hugo Osvaldo Barrera
a68121e439 Update pre-commit hooks 2021-04-18 16:00:39 +02:00
Hugo Osvaldo Barrera
e355b3336b Fix style checks on CI 2021-04-18 15:59:40 +02:00
Hugo Osvaldo Barrera
b435465bc7 Merge style checks into tests
They're both run in pretty much the same environment, and it's
unnecessary to spin up a separate VM for that.
2021-04-09 20:56:21 +02:00
Hugo Osvaldo Barrera
56688a6c50 Avoid installing any dependencies from PyPI
This is to fully ensure that we're using just distribution packages and
not actually fetching newer stuff from PyPI.
2021-04-09 20:01:27 +02:00
Hugo Barrera
bc002a700e
Merge pull request #879 from pimutils/archlinux
Run tests and CI on ArchLinux image
2021-04-07 21:38:07 +00:00
Hugo Osvaldo Barrera
12c860978b Run CI on ArchLinux with repository dependencies 2021-04-07 21:45:43 +02:00
Hugo Osvaldo Barrera
fdc12d561c Update tests to work with hypothesis 6 2021-04-07 21:45:41 +02:00
Hugo Osvaldo Barrera
f549b1d706 Merge branch 'dav_default_ns' 2021-04-07 09:10:53 +02:00
Hugo Osvaldo Barrera
90e8b7b0bc Merge branch 'cleanup' 2021-04-07 09:10:40 +02:00
Hugo Osvaldo Barrera
c5a59ab10b Delete some obsolete leftovers 2021-04-07 08:43:29 +02:00
Hugo Osvaldo Barrera
2685f8db68 Merge master into dav_default_ns 2021-04-07 08:42:29 +02:00
Hugo Barrera
98d28ea2c0
Merge pull request #876 from dilyanpalauzov/typo_a_an
Typo a→an
2021-04-07 06:41:17 +00:00
Дилян Палаузов
ed0b4bef10 Typo a→an 2021-04-07 09:11:15 +03:00
Hugo Barrera
b9c01f8756
Merge pull request #873 from dilyanpalauzov/typo_google
Typo google→Google
2021-04-06 18:33:34 +00:00
Hugo Barrera
de867fcda2
Merge pull request #851 from pimutils/py39
Add support for Python 3.9
2021-04-06 18:33:08 +00:00
Hugo Osvaldo Barrera
1f066ca6ca Remove unused Makefile target 2021-04-06 19:53:00 +02:00
Hugo Osvaldo Barrera
55af4eaf80 Send coverage reports to Codecov 2021-04-06 19:53:00 +02:00
Hugo Osvaldo Barrera
2161de30d0 Avoid docker-compose
The way it handles docker networks breaks builds.
2021-04-06 19:53:00 +02:00
Hugo Osvaldo Barrera
ef34d77ab1 Use Sourcehut for CI 2021-04-06 19:52:57 +02:00
Hugo Osvaldo Barrera
255ea8f9bf This comparison actually does something 2021-04-05 23:28:39 +02:00
Hugo Osvaldo Barrera
8608f37fbb Pin hypothesis 2021-04-05 23:28:39 +02:00
Hugo Osvaldo Barrera
5ed9c821b8 This should work, right?
It's embarrassing that I didn't come up with something so simple before.
2021-04-05 23:28:39 +02:00
Hugo Osvaldo Barrera
53878f001a Horrible, nasty hack 2021-04-05 23:28:39 +02:00
Hugo Osvaldo Barrera
9df587df26 Update CI image
The former one does not support Python 3.9.
2021-04-05 23:28:39 +02:00
Hugo Osvaldo Barrera
8ac4a00306 Add support for Python 3.9 2021-04-05 23:28:39 +02:00
Дилян Палаузов
7750dda980 Typo google→Google 2021-03-18 16:49:08 +02:00
Дилян Палаузов
bf67af609e Substitute the d: prefix for the DAV: namespace with no prefix (default namespace) 2021-03-09 22:23:12 +02:00
Дилян Палаузов
50cb2def73 Add calendar-description, addressbook-description to the meta data
When a CalDAV collection has calendar-description set and vdirsyncer
synchronizes the “meta” data, synchronize also the calendar description.

-- likewise for addressbook-description and calendar-order
2021-03-08 14:57:48 +02:00
Hugo Barrera
6897995080
Merge pull request #870 from tlahn/patch-1
Replace pipsi with pipx
2021-03-07 19:40:19 +00:00
tlahn
31c60021fa
Replace pipsi with pipx
pipsi page says, it is discontinued. Replacing with pipx
2021-03-07 20:10:39 +01:00
Hugo Barrera
a42906b0e8
Merge pull request #859 from pimutils/tarball-includes
Tweak files included in tarballs
2020-12-28 14:25:46 +00:00
Hugo Osvaldo Barrera
f9c6602684 Exclude docker-related files from tarballs 2020-12-28 10:34:32 +01:00
Hugo Osvaldo Barrera
74bb2ffb66 Include contrib in tarballs
Fixes #858
2020-12-28 10:34:25 +01:00
Hugo Barrera
b5d4d3f9a9
Merge pull request #846 from pfactum/master
contrib/systemd: implement service timeout
2020-10-05 15:57:52 +02:00
Oleksandr Natalenko
f79647b29c contrib/systemd: extend timeout to 3 mins
Some people may have mixes of many servers and/or slow connections,
and we'd rather not break for them.

Signed-off-by: Oleksandr Natalenko <oleksandr@natalenko.name>
2020-10-04 22:08:41 +02:00
Oleksandr Natalenko
1de3632620 contrib/systemd: implement service timeout
Sometimes while doing a suspend/resume cycle vdirsyncer can hang in the
middle of sync, and it never bails out afterwards.

Implement a systemd service change that works around this:

* use `simple` (a default) type for `RuntimeMaxSec` to be effective
* actually set `RuntimeMaxSec` to 30 seconds
* trigger service restart on failure

Signed-off-by: Oleksandr Natalenko <oleksandr@natalenko.name>
2020-10-04 20:14:59 +02:00
Hugo Barrera
aeb46ab5a9
Merge pull request #845 from AlecPapierniak/master
Update installation.rst - add closing quote to virtualenv alias
2020-09-09 08:22:17 +00:00
Alec Papierniak
27ebb0902b
Update installation.rst
adding closing quote to virtualenv alias
2020-09-08 22:29:31 -05:00
Hugo Osvaldo Barrera
f281f956f1 Dedupe import 2020-08-06 12:42:00 +02:00
Hugo Osvaldo Barrera
83e5361643 Fix instructions on how to configure timers
Fixes #792
2020-08-06 12:41:05 +02:00
Hugo Osvaldo Barrera
2650a7ed0b Rework packaging guidelines a bit 2020-08-06 12:39:31 +02:00
Hugo Barrera
68ff37e677
Merge pull request #830 from pimutils/next
Keep moving forward
2020-06-10 19:48:15 +00:00
Hugo Osvaldo Barrera
14deb20ce5 Merge remote-tracking branch 'origin/master' into next 2020-06-10 21:10:02 +02:00
Hugo Osvaldo Barrera
5eef4b1ba1 Document GH Releases and signing 2020-06-10 16:42:35 +02:00
Hugo Osvaldo Barrera
7577fa2117 Update usage of deprecated method 2020-06-09 17:04:46 +02:00
Hugo Osvaldo Barrera
1031b07349 Fix test failures that ONLY happen on master 2020-06-09 17:04:22 +02:00
Hugo Osvaldo Barrera
47caebe843 Simplify coverage handling
- Always install coverage tools.
- Show coverage if all tests pass.
- Less conditional code.
2020-06-09 14:57:58 +02:00
Hugo Osvaldo Barrera
3eb9ce5ae4 Add compatibility with latest click 2020-06-09 14:45:02 +02:00
Hugo Osvaldo Barrera
b1b4dd92fe Sort imports
I don't want to ever have to sort imports again. It's a poor use of
developer time. Automate this with a pre-commit hook, and check this on
CI.

Developers: I suggest you configure your editor to use
`reorder_python_imports`. It uses the standard sorting, and detects
first/third party libs well.
2020-06-09 14:34:45 +02:00
Hugo Osvaldo Barrera
9cb1f8d704 Drop support for Python 3.5 and 3.6 2020-06-09 14:33:14 +02:00
Hugo Osvaldo Barrera
56b1fc2187 Remove now-unused Makefile target 2020-06-09 14:17:56 +02:00
Hugo Osvaldo Barrera
b5dd0929d0 Add GitHub Action to publish releases 2020-06-09 14:10:52 +02:00
Hugo Barrera
d854bd62eb
Merge pull request #825 from pimutils/next
Support Python 3.7 and 3.8
2020-06-09 11:30:34 +00:00
Hugo Osvaldo Barrera
f6e6b0b6c3 Prepare release 0.16.8 2020-06-09 13:27:35 +02:00
Hugo Osvaldo Barrera
399274286e Add classifiers for Python 3.7 and 3.8 2020-06-09 13:01:22 +02:00
Hugo Osvaldo Barrera
be59ba5ab4 Run tests with newer Python versions
We also need different Ubuntu dists for different pythons on travis.
2020-06-09 12:56:10 +02:00
Hugo Osvaldo Barrera
6e59ee0b5f Add a pre-commit hook to rebuild travis config 2020-06-09 12:37:53 +02:00
Hugo Barrera
82375f20aa
Merge pull request #823 from pimutils/next
Run test servers with Docker
2020-06-09 09:47:54 +00:00
Hugo Osvaldo Barrera
cd86ea7a62 Run storage tests for ETESYNC too 2020-06-09 11:29:54 +02:00
Hugo Osvaldo Barrera
354aaec2e0 Only run CI for branch master
For PRs, CI will run on the PR itself, so no need to run it for the
branch (otherwise we get duplicate jobs, and it's sooooo slow!).
2020-06-09 10:46:17 +02:00
Hugo Osvaldo Barrera
af3659ac1a Update contributing instructions 2020-06-09 10:42:26 +02:00
Hugo Osvaldo Barrera
50eefa1816 Use pre-commit for CI style checks
Have a single, uniform definition everywhere.
2020-06-09 10:42:14 +02:00
Hugo Osvaldo Barrera
53331fedee Skip unsupported radicale test 2020-06-09 10:42:14 +02:00
Hugo Osvaldo Barrera
88f2cd5b53 Skip VTODO items for Fastmail
See #824
2020-06-09 10:42:14 +02:00
Hugo Osvaldo Barrera
4f894e04dd Empty noop script 2020-06-09 10:42:14 +02:00
Hugo Osvaldo Barrera
0319035688 Don't run unit/system tests for each storage
The current storage (DAV_SERVER) has no impact on unit tests and system
tests, so rather than run all these tests for each server, just run them
once per python.
2020-06-09 10:42:11 +02:00
Hugo Osvaldo Barrera
6c6da2f613 Test baikal using docker 2020-06-09 09:49:18 +02:00
Hugo Osvaldo Barrera
b0d8fd34dc Test radicale with docker too 2020-06-09 09:49:16 +02:00
Hugo Osvaldo Barrera
0f3b2e74c0 Test xandikos running it in docker
The main advantage here is that its dependencies are TOTALLY separate
from vdirsyncer's, keeping the runtime environment for vdirsyncer
cleaner.

It also makes testing locally not only possible, but fast and pleasant.
2020-06-09 09:49:03 +02:00
Hugo Osvaldo Barrera
c410fbf331 Enable docker on travis 2020-06-09 09:46:27 +02:00
Hugo Osvaldo Barrera
f1f51ac3cf Don't fix EOF in travis.yml
Since this is auto-generated, it... conflicts in complicated ways. 😞
2020-06-09 09:46:27 +02:00
Hugo Osvaldo Barrera
3037c15a65 Use hypothesis setting load_profile to setup health check
Fixes #779
2020-06-08 19:58:35 +02:00
Romain
e5caf6750d Add double quote in exemple config files (#732)
* nextcloud.rst : add double quote to not forget them

Add double quote to not forget them, and avoid the message :
warning: Soon, all strings have to be in double quotes. Please replace UserName with "UserName"

* fastmail.rst : add double quote to not forget them

Add double quote to not forget them, and avoid the message :
warning: Soon, all strings have to be in double quotes. Please replace UserName with "UserName"

* icloud.rst : add double quote to not forget them

Add double quote to not forget them, and avoid the message :
warning: Soon, all strings have to be in double quotes. Please replace UserName with "UserName"

* todoman.rst : add double quote to not forget them

Add double quote to not forget them, and avoid the message :
warning: Soon, all strings have to be in double quotes. Please replace UserName with "UserName"

* xandikos.rst : add double quote to not forget them

Add double quote to not forget them, and avoid the message :
warning: Soon, all strings have to be in double quotes. Please replace UserName with "UserName"

* davmail.rst : add double quote to not forget them

Add double quote to not forget them, and avoid the message :
warning: Soon, all strings have to be in double quotes. Please replace UserName with "UserName"

* partial-sync.rst : add double quote to not forget them

Add double quote to not forget them, and avoid the message :
warning: Soon, all strings have to be in double quotes. Please replace UserName with "UserName"
2020-06-08 19:58:35 +02:00
Markus Unterwaditzer
f0fe104427 Credit packagecloud
Because we asked packagecloud for more bandwidth, they asked us to
credit them in the README
2020-06-08 19:58:35 +02:00
Hugo Osvaldo Barrera
5c3900500d Update link to official Arch package (#710)
There's now an official Arch package
2020-06-08 19:58:35 +02:00
Markus Unterwaditzer
6befffcc45 Screw git hooks 2020-06-08 19:58:35 +02:00
Markus Unterwaditzer
22717ee217 Add simple doc for todoman 2020-06-08 19:58:35 +02:00
Amanda Hickman
c78ec6b3bd Little spelling fix (#695)
* Fixed spelling of "occurred"

* Fix spelling of occurred.

* fixed one lingering misspelling
2020-06-08 19:58:35 +02:00
Hugo Osvaldo Barrera
289f60da44 Update copyright year 2020-06-08 19:58:35 +02:00
Malte Kiefer
69e235c35d fixed typo (#678)
fixed typo
2020-06-08 19:09:59 +02:00
Markus Unterwaditzer
5a2032d6d9 Add fast_finish to Travis 2020-06-08 19:09:59 +02:00
Markus Unterwaditzer
fb68a6c4aa Fix broken link 2020-06-08 19:09:59 +02:00
Markus Unterwaditzer
107edfd52d Fix installation link 2020-06-08 19:09:59 +02:00
Hugo Osvaldo Barrera
60e2e9669e Merge branch 'next' 2020-06-08 18:59:37 +02:00
Thomas Klausner
b1214cd693 Follow advice from setuptools_scm how to use it.
See https://github.com/pypa/setuptools_scm
2020-06-08 18:58:27 +02:00
/\/\ \-/ ❭❬
3d7d92c2d6 baikal-server.com does not work anymore 2020-06-08 18:56:26 +02:00
5472qaywsx
59740b379f Update claws-mail.rst
Fixed some (2) minor typos.
Actually, all I wanted to do is to fix typo "contab -e" -> "crontab -e" of page "https://vdirsyncer.pimutils.org/en/stable/tutorials/claws-mail.html", but seems already correct on github...

Closes #803
2020-06-08 18:53:12 +02:00
Hugo Osvaldo Barrera
461e4c55b0 Update servers for Fastmail
Fixes #785
2020-06-08 18:50:03 +02:00
Hugo Osvaldo Barrera
a5b98517e8 Remove broken waffle badge 2020-06-08 18:45:04 +02:00
Hugo Osvaldo Barrera
1e425a590a Run CI on this branch too 2020-06-08 18:41:55 +02:00
Hugo Osvaldo Barrera
308289febf Remove python2 leftover code 2020-06-08 18:40:33 +02:00
Hugo Osvaldo Barrera
eece9a6bde Update requests
2.20.0 is almost two years old, so we can safely assume anyone wanting a
recent vdirsyncer can upgrade.

It's also the first version to include several upstream security fixes
which I'd rather we depend on too.
2020-06-08 18:40:33 +02:00
Hugo Osvaldo Barrera
a26d3bb58c Update hypothesis 2020-06-08 18:40:33 +02:00
Hugo Osvaldo Barrera
e2d3c1add7 Add pre-commit hooks with some basic linting
Mostly to keep an eye on code quality as I move forward.
2020-06-08 18:40:33 +02:00
Hugo Osvaldo Barrera
b4bbc5946a Simplify travis setup a bit 2020-06-08 18:40:33 +02:00
Hugo Osvaldo Barrera
7e4a0be674 Upgrade flake8
Update to the latest flake8, and fix all code warnings related to that.
2020-06-08 18:40:31 +02:00
Hugo Osvaldo Barrera
aafafaa501 Pin dependencies for ete tests 2020-06-08 17:16:28 +02:00
Hugo Osvaldo Barrera
9505430b83 Pin an older version of Xandikos
This is the one used back when master was last green, so let's start
with this one and gradually move up.
2020-06-08 16:33:17 +02:00
Hugo Osvaldo Barrera
216ce8d180 Disable CI on OSX for now
Just gets in the way, and no change of having that green until we update
a lot of other things.
2020-06-08 16:33:12 +02:00
Hugo Osvaldo Barrera
cb4ba5b38c Fix linting errors
One more green checkmark! 
2020-06-08 15:39:01 +02:00
Hugo Osvaldo Barrera
72ea0a6ad3 Pin etesync 2020-06-08 15:31:20 +02:00
Hugo Osvaldo Barrera
810349eef0 Pin an older flake8 until we get around to linting 2020-06-08 15:00:38 +02:00
Hugo Osvaldo Barrera
65d17bdcbf Pin a known-working version of radicale too 2020-06-08 14:47:41 +02:00
Hugo Osvaldo Barrera
470c2c6630 Don't test with devel versions
There's no chance this is going to work -- we've a lot of catching up to
do in this aspect.
2020-06-08 14:44:55 +02:00
Hugo Osvaldo Barrera
7c04289ed4 Pin xandikos to 0.1.0 2020-06-08 13:51:15 +02:00
Hugo Osvaldo Barrera
e987d6eb4a Drop Python 3.4
Never gonna get master back to green working with a dead Python.
2020-06-08 13:34:17 +02:00
Hugo Osvaldo Barrera
558da29e5e Use the syntax hypothesis accepts 2020-06-08 13:26:39 +02:00
Hugo Osvaldo Barrera
83fe7d2c8a Pin dependencies to older versions
Just to get master back up and running again, pin libraries to the
versions we used back when the latest development happened.

I'll start upgrading them gradually, but need a green master first.
2020-06-08 13:15:27 +02:00
Martin Michlmayr
78599a131d Fix typos 2020-06-08 13:02:36 +02:00
Markus Unterwaditzer
dcf5f701b7 Version 0.16.7 2018-07-19 21:15:29 +02:00
Markus Unterwaditzer
80a42e4c6c Fixes for open_graphical_browser, fixes #754 2018-07-19 21:14:30 +02:00
Markus Unterwaditzer
aec9b91602 version 0.16.6 2018-06-13 18:54:27 +02:00
Markus Unterwaditzer
7e6d618ccf restore release date 2018-06-13 18:54:12 +02:00
Markus Unterwaditzer
1f9668393c stylefix 2018-06-13 18:53:14 +02:00
Markus Unterwaditzer
f1cc05af62 fix config parameter formatting 2018-06-13 18:49:43 +02:00
Markus Unterwaditzer
6c652c9b7a fix etesync formatting 2018-06-13 18:35:04 +02:00
Markus Unterwaditzer
68f2cf3195 (backport) Make docs build independent of app 2018-06-13 18:25:10 +02:00
Markus Unterwaditzer
0094acddd0 version 0.16.5 2018-06-13 18:01:23 +02:00
Markus Unterwaditzer
83026ad7de require click-log 0.3.0 2018-06-13 18:00:01 +02:00
Markus Unterwaditzer
97f58ddc46 Disable health checks for distro builds 2018-02-05 17:01:37 +01:00
Markus Unterwaditzer
c63e55d020 Version 0.16.4 2018-02-05 15:50:23 +01:00
Markus Unterwaditzer
dde30c22be Ignore new flake8 linters 2018-02-05 15:45:31 +01:00
Markus Unterwaditzer
250bd974f3 Flake8: ignore eggs dir 2018-02-05 15:45:09 +01:00
Markus Unterwaditzer
a5ed1eb98f Disable a few builds 2018-02-05 15:39:16 +01:00
Markus Unterwaditzer
19dd9df091 Always upgrade dependencies 2018-02-05 08:36:22 +01:00
Markus Unterwaditzer
93df284d3c Make a maintenance release of vdirsyncer, fix #708 2018-02-05 08:23:45 +01:00
Markus Unterwaditzer
cca412e7a8 Version 0.16.3 2017-10-03 10:57:47 +02:00
Markus Unterwaditzer
9e3c231cc3 Remove Python 3.3 support (#674)
* Remove Python 3.3 support
2017-10-02 14:38:54 +02:00
Markus Unterwaditzer
1f8d1a0dc5 More tests for sync status 2017-10-01 22:29:33 +02:00
Markus Unterwaditzer
be33fd3ed3 Restructure vdirsyncer.sync 2017-10-01 21:44:14 +02:00
Markus Unterwaditzer
32d1fecbb4 New tests for sync status 2017-10-01 21:44:14 +02:00
Markus Unterwaditzer
c507e12e0d Fix small behavioral oddity in makefile 2017-10-01 21:44:14 +02:00
Markus Unterwaditzer
af4cb4624c Remove annoying extra arg again 2017-10-01 21:44:14 +02:00
Markus Unterwaditzer
cf8e89b5b4 Split up fetchparams tests 2017-10-01 21:44:14 +02:00
Markus Unterwaditzer
c6cc45c4b4 Update setuptools in Travis 2017-09-25 20:14:02 +02:00
Markus Unterwaditzer
944d5e709c Also update setuptools 2017-09-25 20:12:58 +02:00
Markus Unterwaditzer
88969ae5e6 Fix xandikos git url 2017-09-24 12:02:24 +02:00
Markus Unterwaditzer
4e2c5e51f3 Make git hooks optional 2017-09-24 12:00:45 +02:00
Markus Unterwaditzer
8495d87196 Remove requirement of filenames being UIDs (#672) 2017-09-23 13:58:03 +02:00
Markus Unterwaditzer
9314a93d67 Add autopep8 git commit hook (#671)
* Add autopep git hook

* Fix broken link
2017-09-23 13:55:57 +02:00
Markus Unterwaditzer
e2583ededf Use travis' new conditional branches (#670)
See https://github.com/travis-ci/travis-ci/issues/2778#issuecomment-329968553
See https://docs.travis-ci.com/user/conditional-builds-stages-jobs/#Conditional-Jobs
2017-09-23 13:55:30 +02:00
Markus Unterwaditzer
18a4f93c97 Rewrite pitch 2017-09-23 13:35:09 +02:00
Markus Unterwaditzer
3112e6899e Remove invalid ascii chars from xml, fix #626 (#668)
* Remove invalid ascii chars from xml, fix #626

* Add changelog

* Remove unused imports

* Fix errors on older Python versions

* Fix tests
2017-09-13 20:55:03 +02:00
Markus Unterwaditzer
77658fa0b5 Disable urllib3 warnings 2017-09-11 21:25:56 +02:00
Markus Unterwaditzer
d6268f24a1 Install google dependencies in debian pkgs 2017-09-08 19:31:34 +02:00
Markus Unterwaditzer
414292bc50 Remove leftover 2017-09-02 19:51:16 +02:00
Markus Unterwaditzer
ebafa3b69b Don't use dist dir for debian pkgs 2017-09-02 19:20:15 +02:00
Markus Unterwaditzer
ab798568ac Faster debian package build 2017-09-02 18:50:34 +02:00
Markus Unterwaditzer
cc91f334e7 Add note that debian packages are for 64-bit only 2017-09-02 15:24:11 +02:00
Markus Unterwaditzer
189668400e Changelog for #663 2017-08-31 20:02:47 +02:00
Markus Unterwaditzer
131b3d257d Debian packaging (#664) 2017-08-30 21:57:38 +02:00
Markus Unterwaditzer
1da0bd1cdd Version 0.16.2 2017-08-24 13:48:53 +02:00
Markus Unterwaditzer
6954b26e0f Fixes for click-log 0.2.0 2017-08-24 13:29:20 +02:00
Oliver Schmidhauser
9930b4b3ca Remove superfluous diacritic from documentation. (#662) 2017-08-24 13:13:35 +02:00
Markus Unterwaditzer
35ffdd6f8c Fix crash in google calendar when using filters
Fix #657
2017-08-15 14:05:52 +02:00
Markus Unterwaditzer
c9a085522f Abort discovery on UserError 2017-08-15 14:05:09 +02:00
Markus Unterwaditzer
8565277623 Revert "Disable iCloud tests"
This reverts commit b7e7cfc439.

See #646
2017-08-13 14:25:59 +02:00
Markus Unterwaditzer
395e8276de Change warning to debug, see #658 2017-08-12 17:01:47 +02:00
Markus Unterwaditzer
629de5558d Remove babbling about abstract interfaces 2017-08-12 16:56:32 +02:00
Markus Unterwaditzer
0d47e06d89 Add test re #657 2017-08-12 16:46:22 +02:00
Markus Unterwaditzer
e305869fac Simplify code a little 2017-08-12 16:26:16 +02:00
Markus Unterwaditzer
6e27770271 Version 0.16.1 2017-08-08 20:13:30 +02:00
Markus Unterwaditzer
2d6125f8eb Changelog for #660 2017-08-08 20:13:05 +02:00
Markus Unterwaditzer
547b327557 Attempt to fix requests tests 2017-08-02 19:55:56 +02:00
Markus Unterwaditzer
9bba4bb9fe Actually link to docs 2017-07-20 19:06:04 +02:00
Markus Unterwaditzer
dfc9f1aa3f Add xandikos test example 2017-07-20 19:06:04 +02:00
Jelmer Vernooij
01c88b514c Set defaults for CI and DETERMINISTIC_TESTS. (#653)
This makes it a bit easier to manually run individual tests.
2017-07-19 21:40:52 +02:00
Markus Unterwaditzer
bde00c227a Document makefile options
See #653
2017-07-19 21:40:25 +02:00
Markus Unterwaditzer
3bb51f81f1 Document #535 2017-07-17 20:15:20 +02:00
Markus Unterwaditzer
56fe38fcdc UID replacement benchmark 2017-07-16 22:17:04 +02:00
Markus Unterwaditzer
e3060529a5 Move from deprecated readfp to read_file 2017-07-15 22:50:59 +02:00
Markus Unterwaditzer
3affea685a Remove pypy3 from build matrix (#649) 2017-07-07 20:00:14 +02:00
Markus Unterwaditzer
37a1eb2fdb Remove remoteStorage (#648)
Fix #647
2017-07-02 18:42:55 +02:00
Markus Unterwaditzer
bf79ac1748 stylefix 2017-07-02 17:17:26 +02:00
Markus Unterwaditzer
d5db9357f9 Don't test any servers under Pypy3 2017-07-02 16:37:40 +02:00
Markus Unterwaditzer
c0a6fb1b41 Run only tests 2017-07-02 16:16:16 +02:00
Markus Unterwaditzer
87c7143fa4 Version 0.16.0 2017-07-02 02:13:58 +02:00
Markus Unterwaditzer
5259ffd00e fix readme 2017-07-02 02:13:14 +02:00
Markus Unterwaditzer
76df8a3032 Tidy up changelog 2017-07-02 00:36:39 +02:00
Markus Unterwaditzer
b7e7cfc439 Disable iCloud tests
see #646
2017-07-02 00:29:24 +02:00
Markus Unterwaditzer
a96f358464 Move donations to doc page 2017-06-28 11:42:55 +02:00
Markus Unterwaditzer
95d5b2c1b9 Typo fix 2017-06-20 18:13:30 +02:00
Damien Cassou
a2cbbbb9d1 Discuss command syntax in tutorial's conflict resolution section (#644) 2017-06-19 16:43:07 +02:00
Markus Unterwaditzer
527acb2617 Disable tests for xandikos on pypy3 2017-06-14 17:47:12 +02:00
Markus Unterwaditzer
fb558e5139 Remove stray debug print 2017-06-10 21:24:33 +02:00
Markus Unterwaditzer
fb3641f3c1 Also run xandikos with release requirements 2017-06-08 01:00:24 +02:00
Markus Unterwaditzer
72eae0a4d3 More dev packages 2017-06-08 00:46:17 +02:00
Markus Unterwaditzer
c3cefd7046 Clear pyenv installation before installing pyenv 2017-06-07 23:49:09 +02:00
Markus Unterwaditzer
7dcd4d5118 docs: Fastmail is now tested 2017-05-31 14:27:19 +02:00
Markus Unterwaditzer
fdff446e92 Update pypy3 2017-05-31 14:21:53 +02:00
Markus Unterwaditzer
9d393623fd Fix error message if etesync is not installed 2017-05-31 13:56:10 +02:00
Markus Unterwaditzer
76b9bb0aa1 Travis: Upgrade to trusty 2017-05-31 13:44:40 +02:00
Markus Unterwaditzer
fa6a98ec9b Remove useless skip 2017-05-31 12:40:40 +02:00
Markus Unterwaditzer
6a273953f7 Fix xandikos test: multistatus parsing 2017-05-30 11:25:52 +02:00
Markus Unterwaditzer
7f80251527 Test development Radicale again (#428)
* Revert "Don't test development Radicale"

This reverts commit 7a5241101e.

* Fix Radicale test setup

* Radicale is very tolerant

* Simplify test such that output is more predictable

* Runtime version check for Radicale

* Don't create user explicitly

* stylefix

* Shorter tracebacks

Travis logs are very hard to read
2017-05-30 09:12:00 +02:00
Markus Unterwaditzer
5f3c14ef7d Restructure supported.rst into tutorial subpages (#631)
* Restructure supported.rst into tutorial subpages

Fix #623

* Fix section headings and whitespace

* fix link

* Stylefix
2017-05-29 02:50:39 +02:00
Hugo Osvaldo Barrera
1bf863c615 Add systemd.timer files and a relevant tutorial (#635)
Include a systemd.timer file (the interval can be overridden, as
mentioned in the docs). TBH, I'd suggest downstream packagers of
systemd-based distributions include these files on installation
(activation needs to be done manually anyway).
2017-05-24 22:38:42 +02:00
Markus Unterwaditzer
d2127030c2 Use inode number in addition to mtime (#632)
* Use inode number in addition to mtime

* Changelog
2017-05-18 20:42:08 +02:00
Markus Unterwaditzer
6851ceede0 Better useragent (#633) 2017-05-18 20:41:52 +02:00
Doron Behar
34dc84c29f Add more instructions regarding docs/keyring.rst. (#624)
* Add more instructions regarding `docs/keyring.rst`.

Add minimal explanation for using external password manger named `pass`
to automatically safely and fetch the password.

* Some fixups
2017-05-05 23:21:26 +02:00
Sandro Santilli
9e1adf877e More quoting (#630) 2017-05-04 15:08:40 +02:00
Sandro Santilli
609434fe76 Properly quote "b wins" (#629)
avoids a warning on use
2017-05-04 13:22:04 +02:00
Markus Unterwaditzer
8a5df8b802 stylefix 2017-05-02 13:56:57 +02:00
Markus Unterwaditzer
2b0492fe5e Fix etesync tests 2017-05-02 12:58:58 +02:00
Markus Unterwaditzer
cc54ed6e7c Migrate etesync db 2017-04-29 21:33:50 +02:00
Markus Unterwaditzer
83531f95e5 Fix NameError 2017-04-27 16:50:21 +02:00
Markus Unterwaditzer
09dacde3f3 owncloud update 2017-04-18 23:12:32 +02:00
Markus Unterwaditzer
5a8b141b53 Fix MANIFEST.in 2017-04-18 16:01:39 +02:00
Markus Unterwaditzer
1ed6d4db0a Add reference 2017-04-15 12:04:09 +02:00
Markus Unterwaditzer
3f6c135806 More discovery docs (#621) 2017-04-14 10:01:58 +02:00
Markus Unterwaditzer
97708ab3da Fix shitty exception 2017-04-13 18:41:37 +02:00
Markus Unterwaditzer
b0cd233f81 Changelog for #614 2017-04-13 18:37:23 +02:00
Markus Unterwaditzer
3dd132e1b6 Fix import 2017-04-13 16:51:24 +02:00
Markus Unterwaditzer
0d9ec646d7 Initial etesync support (#614)
* Initial etesync support

* Optimized get()

* Bugfixes

* bugfixes

* Add writing operations

* collection creation WIP

* Fix collection creation

* tests wip

* wip

* Final touch for test setup

* actually skip tests

* Disable metadata tests

* Avoid polluting working tree

* Avoid importing wsgi-intercept if not installed

* Fix collection tests

* Proper teardown

* Skip bad test

* Remove vtodo

* wip

* wip

* wip

* wip

* wip

* wip

* wip

* wip

* wip

* Add docs

* Remove useless pkg

* Don't crash if etesync isn't imported

* Stylefix

* Fix more import errors

* More import errors

* Only run etesync on latest python

* Fix etesync check

* journal-manager migration
2017-04-13 16:27:11 +02:00
Markus Unterwaditzer
45d275f71d Disable OS X in Travis (#618)
See #617
2017-04-13 16:26:37 +02:00
Markus Unterwaditzer
7aa0ea20be Relicense to 3-clause BSD, fix #610 2017-04-07 15:32:27 +02:00
Markus Unterwaditzer
b6be4b44de Fix metasync testcase 2017-04-07 12:58:42 +02:00
Markus Unterwaditzer
ef0ef1bdde Remove outdated OS packages
Fix #606
2017-03-31 13:21:15 +02:00
Markus Unterwaditzer
22d7a88063 changelog 2017-03-30 22:48:44 +02:00
Markus Unterwaditzer
dad9fd8904 Ignore directories with leading dot 2017-03-30 22:48:00 +02:00
Markus Unterwaditzer
fbe3f9910d Fix transactions once again 2017-03-29 21:57:34 +02:00
Markus Unterwaditzer
07f6c3af12 Add claws-mail to supported.rst 2017-03-28 18:57:32 +02:00
Markus Unterwaditzer
e7a746705f Fix status migration on Py34 2017-03-28 10:47:09 +02:00
Markus Unterwaditzer
9a32c34e76 Switch to sqlite for sync status (#611)
* Switch to sqlite for sync status

* Add more info to changelog

* Fix transactions

* Fix transactions more
2017-03-28 10:18:24 +02:00
Markus Unterwaditzer
0e89753757 Use sqlite for sync internally (#609)
See #546
2017-03-27 00:08:23 +02:00
Markus Unterwaditzer
00ce809a34 Add openbsd link, thanks @remilocherer 2017-03-25 23:17:20 +01:00
Markus Unterwaditzer
e69360aa50 Enable pip cache 2017-03-23 14:59:51 +01:00
Markus Unterwaditzer
9d2d35f21a fixup! Refine Python 3 warning 2017-03-23 13:55:34 +01:00
Markus Unterwaditzer
2952ea8b15 Refine Python 3 warning 2017-03-23 13:52:00 +01:00
Markus Unterwaditzer
b361fe755c Add Windows warning, see #535 2017-03-23 13:48:06 +01:00
Markus Unterwaditzer
7744070568 Use bash codecov 2017-03-22 16:23:02 +01:00
Markus Unterwaditzer
461fab84ec Use codecov tags 2017-03-22 15:59:54 +01:00
Markus Unterwaditzer
5a508ae327 Abstract status into own class (#607)
* Refactor status management in separate class

* Rename to SubStatus, remove unused field

* Move item cache out of status

* stylefix
2017-03-22 15:08:43 +01:00
Markus Unterwaditzer
28f204162b Add xandikos to CI (#601)
* Add xandikos to CI

* wip

* Work around missing dependency spec

* Add xandikos to travis

* Remove auth

* Test release and devel

* Refactor xandikos setup

* Fix syntax error

* Only test xandikos-git

* Add section to supported.rst

* changelog
2017-03-22 14:40:41 +01:00
Markus Unterwaditzer
bb4a9a1e6c Give up on packaging 2017-03-16 22:08:16 +01:00
Markus Unterwaditzer
f36061969a Fix misformatted doc 2017-03-16 21:56:33 +01:00
Markus Unterwaditzer
fe77532948 remove "Should be easy"-ish remark 2017-03-16 21:30:20 +01:00
Kuba Orlik
5e0dc0d5aa Add quotes to the suggested config (#602)
Without the quotes the app doesn't start, throwing: 

```
critical: Error during reading config /home/kuba/.vdirsyncer/config: Section "general": Section "general", option "status_path": Expecting value: line 1 column 1 (char 0)
```
2017-03-14 16:06:00 +01:00
Markus Unterwaditzer
56b0b48d90 Skip remote tests on PRs 2017-03-14 16:05:30 +01:00
Markus Unterwaditzer
8a1e7a8c3b Make Google syncselect page notice flash out a bit more
Fix #598
2017-03-14 11:18:41 +01:00
Markus Unterwaditzer
ceb6296669 Add trailing slash on discovery (#600) 2017-03-14 11:12:44 +01:00
Markus Unterwaditzer
a217623e8e Fix deprecation warning 2017-03-14 11:09:43 +01:00
Markus Unterwaditzer
e5bc3fd6e7 Document resolution of #593 2017-03-12 13:36:12 +01:00
Markus Unterwaditzer
e1af47b1aa Refactor makefile 2017-03-12 13:26:52 +01:00
Markus Unterwaditzer
ba17fe6135 Reformat examples in CLI help (#594) 2017-03-12 13:10:12 +01:00
Markus Unterwaditzer
06017c39c0 Document that gcal doesn't support VTODO (#592) 2017-03-09 19:33:47 +01:00
Markus Unterwaditzer
a285c555f0 Ignore fs collections that have subfolders (#591)
Fix #588
2017-03-09 13:40:27 +01:00
Markus Unterwaditzer
feea65ff1d Stylefix 2017-03-08 11:38:57 +01:00
Markus Unterwaditzer
bb35d7c091 Flatten mysteryshack submodule 2017-03-08 10:16:26 +01:00
Markus Unterwaditzer
a02f36f0cb Flatten davical submodule 2017-03-08 10:14:07 +01:00
Markus Unterwaditzer
c15a04a1de Expand flake8 to submodules 2017-03-08 10:08:24 +01:00
Markus Unterwaditzer
bada6abfc6 Make discovery more RFC-conformant (#585)
* Make discovery more RFC-conformant

Fix #584
2017-03-08 09:36:10 +01:00
Christian Geier
7fc5f1bf23 Fixed some typos. (#587)
I installed mwic, so you don't have to.
`unperformant` doesn't seem to be an often used english word either and
`addressbook` is probably `address book`.
2017-03-07 22:12:04 +01:00
Markus Unterwaditzer
785bf52d73 Fix crash when saving token file 2017-03-07 16:12:23 +01:00
Markus Unterwaditzer
3b713a14ab Fix link 2017-03-03 17:31:12 +01:00
Markus Unterwaditzer
4027e077e7 Fix crash when discovery fails
See #574
2017-03-02 22:00:05 +01:00
Markus Unterwaditzer
b722e5aec5 Make subpackage a module 2017-03-02 21:56:40 +01:00
Markus Unterwaditzer
335c7062fd Make subpackage a module 2017-03-02 21:56:06 +01:00
Markus Unterwaditzer
ae2542c992 flake8: Enable B902 2017-03-02 21:30:42 +01:00
Markus Unterwaditzer
668220dbd7 Add fastmail testserver (#572) 2017-03-02 21:13:08 +01:00
Tomas Babej
325298bf51 config.example: Status path needs to be quoted (#573) 2017-03-02 15:45:07 +01:00
Markus Unterwaditzer
4de920b552 Ignore METHOD prop while hashing 2017-03-02 14:52:17 +01:00
Markus Unterwaditzer
38599e1666 Strip method:publish, fix #502 2017-03-02 14:45:11 +01:00
Markus Unterwaditzer
968b416cc5 Version 0.15.0 2017-02-28 18:53:09 +01:00
Markus Unterwaditzer
7914acdeb7 Merge pull request #569 from pimutils/snowflakes!
Check for W503
2017-02-28 13:52:15 +01:00
Markus Unterwaditzer
47a38c0af3 Update submodules 2017-02-28 12:25:45 +01:00
Markus Unterwaditzer
76f794eef3 Module restructuring 2017-02-27 21:19:27 +01:00
Markus Unterwaditzer
83daa8698d Changelog for #567 2017-02-27 19:58:19 +01:00
Markus Unterwaditzer
6aeeb90259 Test iCloud (#567)
* Test iCloud

Fix #149
2017-02-27 19:52:24 +01:00
Markus Unterwaditzer
ded1feb05a Work around Google Contacts discovery bug (#564)
* Work around Google Contacts discovery bug

* fixup

* changelog
2017-02-27 16:06:28 +01:00
Markus Unterwaditzer
96e7c4da37 Fix styling 2017-02-27 00:43:21 +01:00
Markus Unterwaditzer
e457586b29 Fix bug in custom conflict_resolution
Fix #563
2017-02-26 23:24:30 +01:00
Markus Unterwaditzer
b3e389cb59 Enable PyPy3 (#562)
* Enable PyPy3
2017-02-23 16:44:16 +01:00
Hugo Osvaldo Barrera
76d7dcd281 Check for W503 2017-02-20 21:53:56 -03:00
Markus Unterwaditzer
821c70a782 Update IRC link 2017-02-21 01:06:49 +01:00
Markus Unterwaditzer
1790fdd7cc Turn on all opinionated checks 2017-02-20 00:51:50 +01:00
Markus Unterwaditzer
af150ef0ae Roll back change of --list option for discover 2017-02-19 21:40:21 +01:00
Markus Unterwaditzer
19b57f8728 Add link 2017-02-19 20:39:07 +01:00
Markus Unterwaditzer
ccbc01721c Fix missing import 2017-02-18 19:47:09 +01:00
Markus Unterwaditzer
fcd8658b7a Add changelog 2017-02-18 18:33:40 +01:00
Markus Unterwaditzer
cc56a05b7c Create directory automatically 2017-02-18 18:32:52 +01:00
Markus Unterwaditzer
7f38102936 UX improvements for Google storage
Fix #549
Fix #552
2017-02-18 15:54:16 +01:00
Markus Unterwaditzer
10490a12f1 Unconditionally disable HealthCheck.too_slow 2017-02-18 15:45:06 +01:00
Markus Unterwaditzer
c73229e0a9 Reformatting 2017-02-18 13:55:01 +01:00
Markus Unterwaditzer
a6f4232ff9 Merge pull request #559 from somatronicon/master
Adding tip about Microsoft's Remove-DuplicateAppointments.ps1
2017-02-18 12:23:06 +01:00
Christopher Dale
fcf8801863 Add docs around duplicate events w/ davmail
* Adding some documentation around what users can do if they encounter duplicate
  events using DavMail.
2017-02-17 12:20:29 -06:00
Hugo Osvaldo Barrera
7cf0865081 Add trove classifiers (#558) 2017-02-16 17:58:25 +01:00
Markus Unterwaditzer
8d10046fc8 Don't run tests multiple times (#556)
Fix #554
2017-02-15 20:30:00 +01:00
Markus Unterwaditzer
558ea3923a Remove leftovers from hypothesis uploader 2017-02-12 00:53:09 +01:00
Markus Unterwaditzer
9744a3a682 Stylefix 2017-02-12 00:34:42 +01:00
Markus Unterwaditzer
c4dda80e52 Fix tests on mac 2017-02-12 00:28:37 +01:00
Markus Unterwaditzer
ff5732f5ff Restructure tests 2017-02-11 22:53:12 +01:00
Markus Unterwaditzer
c87848fd03 Add example from failing CI run on OS X 2017-02-11 20:25:07 +01:00
Markus Unterwaditzer
0c2157b56b Remove hypothesis CI experiment 2017-02-11 20:25:05 +01:00
Markus Unterwaditzer
9c9620e33f Crash hard if repair fails 2017-02-11 20:24:55 +01:00
Markus Unterwaditzer
7ab6de6f37 More tests 2017-02-11 20:24:55 +01:00
Markus Unterwaditzer
0f2e7e2395 More tests 2017-02-11 20:24:55 +01:00
Markus Unterwaditzer
11694f2766 repair: More tests, slight refactor 2017-02-11 20:24:55 +01:00
Markus Unterwaditzer
e874c38509 Small restructuring for faster imports 2017-02-08 13:48:03 +01:00
Markus Unterwaditzer
62764ae1ef Addendum 2017-02-06 22:02:55 +01:00
Markus Unterwaditzer
cb92b61b8a contributing: Some advice for kanban columns 2017-02-06 22:00:36 +01:00
Markus Unterwaditzer
f993f97dcc Add contact email from pimutils 2017-02-06 21:49:56 +01:00
Markus Unterwaditzer
c6b23b493d Fix weird styling and resource warning in setup.py 2017-02-06 21:22:08 +01:00
Hugo Osvaldo Barrera
38f5dafc1c Remove obsolete conditional imports (#548)
Remove conditional imports left over from python2/3 support.
2017-02-06 21:00:29 +01:00
Markus Unterwaditzer
6a0b95a4bd Update davical testserver 2017-02-06 20:55:00 +01:00
Markus Unterwaditzer
14878e9a5d Add more docs to sync algorithm 2017-02-06 18:15:43 +01:00
Markus Unterwaditzer
960f36ccdc Update installation 2017-02-06 12:53:01 +01:00
Markus Unterwaditzer
007e05a878 Fix README again 2017-02-05 20:54:57 +01:00
Markus Unterwaditzer
6b2450f4ac Fix storage example generator 2017-02-05 14:38:37 +01:00
Markus Unterwaditzer
44206a1e4e Fix flattr link 2017-02-05 14:20:27 +01:00
Markus Unterwaditzer
49deedd416 Fix doc build again 2017-01-30 16:10:29 +01:00
Markus Unterwaditzer
7f43a69de6 Replace donation badges with simple links 2017-01-30 15:22:08 +01:00
Markus Unterwaditzer
9db58e26d0 Fix import error 2017-01-30 15:18:02 +01:00
Markus Unterwaditzer
2890b48cd7 Fix coverage collection 2017-01-30 14:32:25 +01:00
Markus Unterwaditzer
94fe934ec2 Move docs code out of vdirsyncer 2017-01-30 14:09:32 +01:00
Markus Unterwaditzer
e54f5b89a3 Makefile: new coverage param 2017-01-30 13:42:01 +01:00
Markus Unterwaditzer
413e2de45d Refactor CI setup 2017-01-30 13:37:23 +01:00
Markus Unterwaditzer
185abe9ca9 Disable --list for discover 2017-01-30 12:48:18 +01:00
Markus Unterwaditzer
dd465eb909 Don't fail when discovery fails 2017-01-30 12:48:18 +01:00
Markus Unterwaditzer
d454093365 Larger refactor of CLI discovery
Also fix #543
2017-01-29 11:47:47 +01:00
Markus Unterwaditzer
b449287784 Remove superfluous TODO 2017-01-29 11:47:47 +01:00
Markus Unterwaditzer
a3e39f9c7c Run all tests everywhere 2017-01-23 12:56:53 +01:00
Markus Unterwaditzer
3514d7348c More tests for vobject (#541)
* More tests for vobject

* wip

* wip

* stylefix
2017-01-22 23:46:14 +01:00
Malte Kiefer
f756366081 Add claws-mail tutorial (#538)
* Create claws-mail.md

* fix typos

* Change crontab, so you get the erros

* Add @beli3ver to authors

* Convert to rst

* Typo fixes
2017-01-21 12:57:53 +01:00
Markus Unterwaditzer
b10e82b344 Clean up split_collections
The additional function args aren't pretty, but I think this is easier
to grasp.
2017-01-20 23:17:19 +01:00
Markus Unterwaditzer
9c417248de More tests 2017-01-20 23:05:00 +01:00
Markus Unterwaditzer
91a284d60b Remove old logic for config values 2017-01-20 23:05:00 +01:00
Markus Unterwaditzer
0172166510 Stylefix 2017-01-20 21:58:56 +01:00
Markus Unterwaditzer
41794f095d More tests 2017-01-19 22:10:45 +01:00
Markus Unterwaditzer
e7910e92aa Update nextcloud 2017-01-19 14:59:18 +01:00
Markus Unterwaditzer
2e9bccd8b1 Explain new test structure 2017-01-19 13:01:28 +01:00
Markus Unterwaditzer
7d4e28e690 Collect branch coverage 2017-01-18 23:10:40 +01:00
Markus Unterwaditzer
b2422dbea6 Reorganize testsuite
The end goal here is to independently measure coverage of each of those
testsuites.
2017-01-18 22:42:42 +01:00
Markus Unterwaditzer
c9d78e2391 Clarify more docs 2017-01-17 11:46:56 +01:00
Markus Unterwaditzer
3cdd1f6644 Clarify docs 2017-01-17 11:44:59 +01:00
Markus Unterwaditzer
b8ad1def85 Add note about public bountysource donations 2017-01-15 23:24:18 +01:00
Markus Unterwaditzer
7590ff3aef Merge pull request #536 from pimutils/travis-test
Return back to None as non-ETag
2017-01-12 14:17:56 +01:00
Markus Unterwaditzer
af5705f740 Return back to None as non-ETag
nextCloud now returns no etag on upload, which is why we're forced to
adapt the tests accordingly. So now we need to specify a fixed value for
"no etag returned" such that the tests can act accordingly. We also need
to test that the sync algorithm works properly with None.
2017-01-12 13:52:32 +01:00
Markus Unterwaditzer
11922bdcc2 Explain testserver vars of tests 2017-01-07 01:11:58 +01:00
Markus Unterwaditzer
855be466bd Test Python 3.6 2017-01-05 23:57:54 +01:00
Markus Unterwaditzer
2a3e599868 packaging.rst: Remove reference to py2 2017-01-05 23:52:18 +01:00
Markus Unterwaditzer
536d9400c6 Stylefix 2017-01-05 18:55:43 +01:00
Markus Unterwaditzer
5568e4873e Fix more bugs re #523 2017-01-05 18:50:38 +01:00
Markus Unterwaditzer
cc8fe7f773 Version 0.14.1 2017-01-05 17:48:41 +01:00
Markus Unterwaditzer
6280aa6643 Update contributing.rst 2017-01-05 17:46:12 +01:00
Markus Unterwaditzer
d8d1d5b4c7 Update installation.rst again 2017-01-05 17:43:41 +01:00
Markus Unterwaditzer
06817e40d5 Update debian packages 2017-01-05 01:59:39 +01:00
Markus Unterwaditzer
94c9003593 Update DavMail section 2017-01-03 15:25:57 +01:00
Markus Unterwaditzer
45cea7fce2 Stylefix 2017-01-02 18:19:36 +01:00
Markus Unterwaditzer
8f00a6ae39 Refactor sync() to use more classes 2017-01-02 18:19:12 +01:00
Markus Unterwaditzer
31963ca920 Grammar fix 2017-01-02 17:04:02 +01:00
Markus Unterwaditzer
ca57a295eb Recommend letsencrypt in ssl tutorial
See #533
2017-01-02 17:02:58 +01:00
Markus Unterwaditzer
cbdf0f27ae Fix ownCloud docs
Fix #532
2017-01-02 01:13:28 +01:00
Markus Unterwaditzer
21d83ae0d2 Document option default 2016-12-31 17:06:09 +01:00
Markus Unterwaditzer
ad8fc1dc75 Fix changelog typo 2016-12-21 18:09:24 +01:00
Markus Unterwaditzer
11ef34a184 Improve helptext 2016-12-21 18:02:33 +01:00
Markus Unterwaditzer
bd19ee45d8 Stylefix for new bugbear update 2016-12-19 22:18:27 +01:00
Markus Unterwaditzer
e2ef842bb5 Stylefix 2016-12-19 22:12:00 +01:00
Markus Unterwaditzer
b5b3c764d5 Don't test mysteryshack server 2016-12-19 21:21:56 +01:00
Markus Unterwaditzer
c7164cfcca Update mysteryshack 2016-12-10 23:50:02 +01:00
Markus Unterwaditzer
c4d04ad3d7 Baikal and owncloud update 2016-12-10 01:29:28 +01:00
Markus Unterwaditzer
b0f85f9f53 Nextcloud update 2016-12-10 01:27:50 +01:00
Markus Unterwaditzer
c6873c5f18 php servers update 2016-12-10 01:08:19 +01:00
Markus Unterwaditzer
7dcaa47a22 mysteryshack update 2016-12-06 17:45:40 +01:00
Markus Unterwaditzer
96bf21c1da Dont repair unsafe UIDs by default, fix #527 2016-12-06 15:58:16 +01:00
Markus Unterwaditzer
eadb7203ee stylefixes 2016-12-06 15:32:44 +01:00
Markus Unterwaditzer
d1232947c6 Add comment for question #527 2016-12-05 14:19:32 +01:00
Markus Unterwaditzer
e08d096f29 Fix edge case in DAV 2016-11-20 02:58:49 +01:00
Markus Unterwaditzer
9658908118 Fix style 2016-11-10 18:16:41 +01:00
Markus Unterwaditzer
835f8e745e Fix doc link 2016-11-10 15:25:42 +01:00
Markus Unterwaditzer
ef8e3324c6 Debian isn't the only one. 2016-11-10 15:25:15 +01:00
Markus Unterwaditzer
e5be554449 Merge pull request #519 from fpytloun/spelling
Fix spelling error in docs
2016-11-04 12:13:41 +01:00
Filip Pytloun
e17cd96342 Fix spelling error in docs
Resulting in lintian complain:
I: vdirsyncer: spelling-error-in-manpage usr/share/man/man1/vdirsyncer.1.gz errorneous erroneous
2016-11-04 10:44:33 +01:00
Markus Unterwaditzer
dd9394af01 Version 0.14.0 2016-10-26 16:35:42 +02:00
Markus Unterwaditzer
95795476ed Add missing changelog for 1795e63910 2016-10-26 16:35:17 +02:00
Markus Unterwaditzer
5160437f27 Stylefix 2016-10-23 14:20:36 +02:00
Markus Unterwaditzer
db970981a0 Fix tests on OS X 2016-10-23 01:47:09 +02:00
Markus Unterwaditzer
5a257ec2cd config: Add warning about unquoted strings 2016-10-23 01:40:04 +02:00
Markus Unterwaditzer
8171c46b10 Add docs for partial-sync 2016-10-22 23:44:54 +02:00
Markus Unterwaditzer
4da83bfb79 Remove vdirsyncer repl hack 2016-10-22 16:36:24 +02:00
Markus Unterwaditzer
2186178968 Stylefix 2016-10-22 16:22:21 +02:00
Markus Unterwaditzer
1795e63910 Refactor Config API, expose load_config for khal 2016-10-21 13:23:27 +02:00
Markus Unterwaditzer
c6e185d8a3 Evaluate partial_sync lazily
Fix #516
2016-10-13 18:25:55 +02:00
Markus Unterwaditzer
63e9e55bbe SVG Travis badge 2016-10-08 15:54:19 +02:00
Markus Unterwaditzer
39b27532e7 Exclude buggy setuptools-scm version
https://github.com/pypa/setuptools_scm/issues/103
2016-10-05 18:52:47 +02:00
Markus Unterwaditzer
74b73a4011 refactor test_sync 2016-10-04 21:42:31 +02:00
Markus Unterwaditzer
6ecc14fca2 Improve partial sync test 2016-10-04 21:24:59 +02:00
Markus Unterwaditzer
ec00ea70af Rename test 2016-10-04 20:52:53 +02:00
Markus Unterwaditzer
d28527c6ea Run flake8 on Python 3.5 only. 2016-10-04 20:45:47 +02:00
Markus Unterwaditzer
2e3ebd814a Add test for partial_sync=ignore 2016-10-04 20:40:34 +02:00
Markus Unterwaditzer
ff7586fc40 Stylefix 2016-10-04 20:01:08 +02:00
Markus Unterwaditzer
d33c98ac93 Bugfix in config validator 2016-10-04 19:17:38 +02:00
Markus Unterwaditzer
a5eec6193b Prevent setting partial_sync if nothing read-only. 2016-10-04 18:55:47 +02:00
Markus Unterwaditzer
15bf13cfe1 Make pair config more strongly typed 2016-10-04 18:51:11 +02:00
Markus Unterwaditzer
1c030d40ac metasync: Error on invalid conflict resolution 2016-10-04 18:46:57 +02:00
Markus Unterwaditzer
471882fc5e upload-hypothesis: Don't execute on third-party PR 2016-10-03 20:53:25 +02:00
Markus Unterwaditzer
be297b52df Merge pull request #515 from pimutils/partial-sync
Partial sync
2016-10-03 20:52:34 +02:00
Markus Unterwaditzer
fe3f8eabf1 Travis: Fix secret leakage and also upload on PRs 2016-10-03 19:26:02 +02:00
Markus Unterwaditzer
d1495118c0 docs: Clarify importance of make install-dev 2016-10-03 19:26:02 +02:00
Markus Unterwaditzer
6fdee91a5b Changelog for partial_sync 2016-10-03 19:21:30 +02:00
Markus Unterwaditzer
51063f09a6 Improve logging for sync 2016-10-03 19:15:21 +02:00
Markus Unterwaditzer
827299ef24 Add CLI for partial_sync 2016-10-03 19:01:03 +02:00
Markus Unterwaditzer
8ca5446e02 Fix tests 2016-10-03 19:00:27 +02:00
Markus Unterwaditzer
ffeaf25471 internal implementation of partial_sync 2016-10-03 18:37:32 +02:00
Markus Unterwaditzer
497e4a958c sync refactor: get rid of duplicate action designs
Actions are basically an unnecessarily specialized version of the
`*_full`-methods on StorageInfo. This commit makes the API of Actions
more general and removes the `*_full`-methods.
2016-10-03 16:12:49 +02:00
Markus Unterwaditzer
fccc9094c5 Fix changelog dates
Fix #514
2016-10-03 14:27:04 +02:00
Markus Unterwaditzer
4db036a055 upload-hypothesis-db.sh: Avoid usage of cd 2016-10-01 20:50:01 +02:00
Markus Unterwaditzer
13772c67cd Fix bug in makefile 2016-10-01 20:24:47 +02:00
Markus Unterwaditzer
0eda0984f2 Fail if hypothesis-upload fails 2016-10-01 20:09:40 +02:00
Markus Unterwaditzer
3cf33e5efe Stylefix 2016-10-01 19:09:27 +02:00
Markus Unterwaditzer
826a64226e cli-sync: Action failures are non-fatal.
Fix #343
2016-10-01 18:32:05 +02:00
Markus Unterwaditzer
34ac29fc2a Add error_callback to sync() 2016-10-01 18:25:17 +02:00
Markus Unterwaditzer
95c6be6aee Remove remove_hash_from_status
This causes too many problems and forces us to weaken further
assumptions. Better to write separate migration tests, but I don't care.
2016-10-01 17:27:44 +02:00
Markus Unterwaditzer
f7c2aa5f81 Blacklist Sphinx 1.4.7
See https://github.com/sphinx-doc/sphinx/issues/2996
2016-10-01 17:01:23 +02:00
Markus Unterwaditzer
a12df8f5d2 Update mysteryshack again 2016-10-01 16:52:22 +02:00
Markus Unterwaditzer
ef9f13c982 Update mysteryshack again 2016-10-01 16:20:16 +02:00
Markus Unterwaditzer
68d2647e38 Add flake8-bugbear 2016-10-01 16:01:12 +02:00
Markus Unterwaditzer
5dc6a5ff36 Update mysteryshack-testserver (#513)
* Update mysteryshack-testserver

* REMOVE ME

* wip

* wip

* wip
2016-10-01 15:41:18 +02:00
Markus Unterwaditzer
7d0ec9fb32 Version 0.13.1 2016-09-30 09:02:59 +02:00
Markus Unterwaditzer
3aca7e247a Fix bug with combination of yield and return
Thanks van Rossum!
2016-09-30 09:01:49 +02:00
Markus Unterwaditzer
841318208d Version 0.13.0 2016-09-29 18:50:35 +02:00
Markus Unterwaditzer
aede90eee9 Ability to pass homeset-url for DAV storage (#511)
See #509
2016-09-29 18:49:41 +02:00
Markus Unterwaditzer
c9d92ea6eb Fix another bug in uploading script 2016-09-29 18:46:53 +02:00
Steve Peak
0e2d9baf39 fix yaml syntax (#512)
This will fix the status for sure. The comment may be fixed as well since the yaml is now valid

> CC https://github.com/codecov/support/issues/162#issuecomment-250472579
2016-09-29 17:33:44 +02:00
Markus Unterwaditzer
952966b677 Include job number in Hypothesis uploader commits 2016-09-29 16:27:52 +02:00
Markus Unterwaditzer
37ed28d849 Fix up hypothesis uploader again 2016-09-29 16:26:00 +02:00
Travis CI for pimutils
7df4333a77 Hypothesis examples 2016-09-29 13:59:12 +00:00
Markus Unterwaditzer
441509e191 Fix up hypothesis uploader 2016-09-29 15:55:27 +02:00
Markus Unterwaditzer
8f6f44e1fc Remove useless check 2016-09-29 12:26:24 +02:00
Markus Unterwaditzer
373f4b8e77 Add hypothesis example DB to repo 2016-09-29 11:12:45 +02:00
Markus Unterwaditzer
ce8e027346 stylefix 2016-09-27 21:42:29 +02:00
Markus Unterwaditzer
eb5e112293 makefile: Fix default target 2016-09-27 14:20:01 +02:00
Markus Unterwaditzer
565e971e4e Reorganize tests 2016-09-27 14:11:04 +02:00
Markus Unterwaditzer
8e3caf2c58 Extend coverage for repair command 2016-09-27 14:07:12 +02:00
Markus Unterwaditzer
a524f8e971 Debug output 2016-09-27 12:38:36 +02:00
Markus Unterwaditzer
6f4ff7aab1 Replace Dav with DAV
Fix #501
2016-09-27 10:46:17 +02:00
Markus Unterwaditzer
ac3fd8d7fc Elaborate on collections
Fix #444
2016-09-27 10:36:55 +02:00
Markus Unterwaditzer
6aedd624a9 update nextcloud 2016-09-26 20:19:29 +02:00
Markus Unterwaditzer
2cf0aee526 Add known problems for nextcloud 2016-09-26 19:02:47 +02:00
Markus Unterwaditzer
30ab52ea4c Stylefix 2016-09-26 13:28:57 +02:00
Markus Unterwaditzer
5f76c9e720 Another sync refactor 2016-09-26 12:51:49 +02:00
Markus Unterwaditzer
8cbfb69691 Test rollback in sync 2016-09-26 12:51:49 +02:00
Markus Unterwaditzer
4e3d351917 Stylefix 2016-09-25 14:42:41 +02:00
Markus Unterwaditzer
dd5f76ca5d ignore UIDs in http storage 2016-09-25 14:03:46 +02:00
Markus Unterwaditzer
78e11ebb66 Fix missing return value 2016-09-20 09:59:24 +02:00
Markus Unterwaditzer
fbaac88776 Merge pull request #507 from citrin/master
Strip trailing slash from .well-known-URIs to fix autodiscovery
2016-09-19 23:52:34 +02:00
Anton Yuzhaninov
d60132cbc0 Strip slash from well-known URL for Google
According to https://developers.google.com/google-apps/carddav/
URL should be https://www.googleapis.com/.well-known/carddav
2016-09-19 21:50:30 +00:00
Markus Unterwaditzer
5e44f0cfe1 Stylefix 2016-09-19 22:46:07 +02:00
Anton Yuzhaninov
2747bee9a6 Strip trailing slash from .well-known-URIs to fix autodiscovery
According to RFC6764 URLs should be "/.well-known/caldav" and
"/.well-known/caldav".
2016-09-19 18:53:12 +00:00
Markus Unterwaditzer
1087afeaa8 Tone down a warning to an error
Fix #498
2016-09-19 19:44:28 +02:00
Markus Unterwaditzer
722a4be598 ISSUE_TEMPLATE: Clarify importance of debug output 2016-09-19 19:17:39 +02:00
Markus Unterwaditzer
22568571c2 Introduce conflict resolution via commands
Fix #127

More options of conflict resolution are discussed there, but they all
require extra dependencies. This new API allows the user to plug in
third-party scripts to do those.
2016-09-19 19:17:39 +02:00
Markus Unterwaditzer
e62e3a26f6 Better formatting in setup.py 2016-09-19 19:17:39 +02:00
Markus Unterwaditzer
dc5500892b More config refactor 2016-09-19 19:17:39 +02:00
Markus Unterwaditzer
cfbc7ec71b Refactor of status handling in sync (#505)
- Using `info.idents` as new status, this saves a few operations where
  no storage actions have to be taken, but the status has to be updated.

- Rename StorageSyncer to _StorageInfo and make it a private API again.

- Ability to pass custom functions for conflict resolution. This part is
  a preparation for #127.
2016-09-18 15:46:56 +02:00
Markus Unterwaditzer
99e7ff6d37 fix codecov config
See https://github.com/codecov/support/issues/162#issuecomment-246771924
2016-09-13 20:17:30 +02:00
Markus Unterwaditzer
b0c498f70a Don't require current-user-principal
See #498
2016-09-12 18:58:02 +02:00
Markus Unterwaditzer
1846b392fa Fix encoding bug with http data 2016-09-08 14:09:56 +02:00
Markus Unterwaditzer
4354469a93 Changelog for #459 2016-09-08 13:38:37 +02:00
Markus Unterwaditzer
b20fc996a2 Refactor config parsing
Fix #459
2016-09-08 13:34:34 +02:00
Markus Unterwaditzer
18d8bb9fc2 Remove Python 2 support (#499)
* Discontinue Python 2.

See #219

* Remove Python 2 config option

* Remove coerce_native

* Remove PY2 variable

* s/text_type/str/g

* Flake8 fixes

* Remove str = str

* s/to_native/to_unicode/g

* Remove to_unicode = to_unicode

* Remove iteritems

* Remove itervalues

* Remove str import, flake8 fixes

* Remove urlparse compat code

* Remove with_metaclass

* Remove unused PY2 variable

* Remove getargspec_ish

* Remove to_bytes

* Remove compat module

* Remove Python 2 from Travis

* fixup! Remove urlparse compat code

* fixup! Remove urlparse compat code

* fixup! Remove compat module
2016-09-08 12:18:36 +02:00
Markus Unterwaditzer
696e53dc1f Fix up http storage example
Fix #497
2016-09-06 11:32:13 +02:00
Markus Unterwaditzer
b6f009e79e Fix identconflict handling
See #495
2016-09-02 18:23:42 +02:00
Markus Unterwaditzer
5a382be9c6 update davical-testserver 2016-08-28 23:19:22 +02:00
Markus Unterwaditzer
8ecef1e9a6 Update davical
Fix #458
2016-08-27 17:20:10 +02:00
Markus Unterwaditzer
d9387ad0a7 Improve title 2016-08-27 15:49:22 +02:00
Markus Unterwaditzer
ecd35e4a00 Move installation to own page 2016-08-27 15:48:35 +02:00
Markus Unterwaditzer
509b1f5b88 Add debian package 2016-08-27 15:45:23 +02:00
Markus Unterwaditzer
540713f006 Replace with slightly less clever code 2016-08-26 16:58:06 +02:00
Markus Unterwaditzer
d89ec31168 Fix bug in Component.__del__ 2016-08-26 10:36:42 +02:00
Markus Unterwaditzer
12f5d32251 Fix up pytest deprecation warning 2016-08-26 08:35:22 +02:00
Markus Unterwaditzer
0de8415183 Stylefixes 2016-08-26 08:34:32 +02:00
Markus Unterwaditzer
3c7c1f5f67 Add test for CollectionRequired 2016-08-26 01:39:29 +02:00
Markus Unterwaditzer
5ae2d27b66 Refactor IGNORE_PROPS 2016-08-26 00:46:53 +02:00
Markus Unterwaditzer
66031a51e6 Add CODE_OF_CONDUCT.rst for completeness 2016-08-23 23:48:13 +02:00
Markus Unterwaditzer
6bed4f504e Add the CoC to this project 2016-08-23 23:45:22 +02:00
Markus Unterwaditzer
6f43e14908 Update baikal-testserver 2016-08-23 16:05:47 +02:00
Markus Unterwaditzer
a05c30be58 Update mysteryshack-testserver 2016-08-20 17:14:26 +02:00
Markus Unterwaditzer
8645310422 Version 0.12.1 2016-08-20 11:41:14 +02:00
Markus Unterwaditzer
902d914db6 Remove = from reserved chars
See #491
2016-08-19 20:05:14 +02:00
Markus Unterwaditzer
e1c2e1b5d8 Fix bug in URL normalization 2016-08-19 20:05:14 +02:00
Markus Unterwaditzer
f238a58c85 DAV: Don't violate Storage API (#492)
The implementation of #476 is problematic as it returns None.
`vdirsyncer.sync` has internal assertions that this is a string, which
is why we get a crash like this:

    error: Unknown error occured for cal/markus@unterwaditzer.net:
    error: Use `-vdebug` to see the full traceback.
    debug:   File "/home/untitaker/projects/vdirsyncer/vdirsyncer/cli/tasks.py", line 66, in sync_collection
    debug:     force_delete=force_delete
    debug:   File "/home/untitaker/projects/vdirsyncer/vdirsyncer/sync.py", line 228, in sync
    debug:     action(a_info, b_info, conflict_resolution)
    debug:   File "/home/untitaker/projects/vdirsyncer/vdirsyncer/sync.py", line 276, in inner
    debug:     assert isinstance(dest_etag, (bytes, text_type))

Discovered in #467
2016-08-19 19:58:38 +02:00
Markus Unterwaditzer
f8dffaf51e Update mysteryshack-testserver 2016-08-19 19:11:58 +02:00
Markus Unterwaditzer
214ec10826 Add CREATED to ignored properties 2016-08-19 17:36:17 +02:00
Markus Unterwaditzer
9a4dbef3a9 Version 0.12.0 2016-08-19 12:36:21 +02:00
Markus Unterwaditzer
4b4ed83df2 Fix broken formatting in changelog 2016-08-18 13:14:20 +02:00
Markus Unterwaditzer
5606f3171a Changelog for #488 2016-08-17 17:42:39 +02:00
Markus Unterwaditzer
a54999ff17 Introduce collections for singlefile storage (#488)
Fix #485
2016-08-17 17:41:40 +02:00
Markus Unterwaditzer
e9185324ae Fix up links for new docs URL 2016-08-15 20:44:45 +02:00
Markus Unterwaditzer
4ca4f13423 Update nextCloud 2016-08-15 13:05:40 +02:00
Markus Unterwaditzer
d96ad6ad10 Update mysteryshack-testserver again 2016-08-15 12:48:14 +02:00
Markus Unterwaditzer
7b81415b58 Update mysteryshack-testserver 2016-08-15 12:36:49 +02:00
Markus Unterwaditzer
c099b876d2 Syntax fix 2016-08-15 12:12:49 +02:00
Markus Unterwaditzer
3deba27d8b Make test_collection_arg more generic 2016-08-15 11:25:37 +02:00
Markus Unterwaditzer
bec3a81186 Restructure setup.py
See #487
2016-08-13 12:05:32 +02:00
Markus Unterwaditzer
dc8c1402c2 Version 0.11.3 2016-07-29 15:46:48 +02:00
Markus Unterwaditzer
707c824c2b Revert "Run all tests in PR" (#483) 2016-07-26 21:49:47 +02:00
Martin Zimmermann
48d72aa7a1 fully resolve well-known URI (#481)
Currently, `find_dav` only resolves a single redirect. When using
Baïkal behind a proxy with HTTPS, this becomes an issue:

1. dav.example.com/.well-known/caldav (Apache rewrite to http)
2. dav.example.com/dav.php (http)
3. dav.example.com/dav.php (https)

The Apache configuration is provided by Baïkal, hence it is also
possible to fix it server-side:

  -RewriteRule /.well-known/carddav /dav.php [R,L]
  +RewriteRule /.well-known/carddav https://dav.example.com/dav.php [R,L]
  -RewriteRule /.well-known/caldav /dav.php [R,L]
  +RewriteRule /.well-known/caldav https://dav.example.com/dav.php [R,L]
2016-07-26 21:49:17 +02:00
Markus Unterwaditzer
97bfccdb44 Stylefix for flake8 update 2016-07-26 21:48:42 +02:00
Markus Unterwaditzer
f7076118df Stylefixes 2016-07-25 04:58:10 +02:00
Markus Unterwaditzer
d8a1fb4a62 Always use string header values
Preparing for https://github.com/kennethreitz/requests/issues/3386
2016-07-25 04:58:10 +02:00
Markus Unterwaditzer
140af81ead Fix XML querying bug
Fix #480
2016-07-25 04:58:10 +02:00
Markus Unterwaditzer
4df423b93e Correct click-threading requirement
Fix #478
2016-07-25 01:51:06 +02:00
Markus Unterwaditzer
e4a0afcf00 Make auth = basic the default again (#477)
Fix #461
Fix #457
2016-06-17 14:35:06 +02:00
Markus Unterwaditzer
3228e22621 DAV: Fix behavior when PUT doesn't return ETag (#476)
Thanks to @evert for pointing this out in the #sabredav IRC channel.
2016-06-16 21:40:18 +02:00
Markus Unterwaditzer
5b87dcceeb Merge pull request #475 from pimutils/all-tests-in-pr
Run all tests in PR
2016-06-16 18:15:15 +02:00
Markus Unterwaditzer
df5545946e Run all tests in PR
The current behavior is annoying in combination with homu.io

Reverts #387
2016-06-16 17:44:09 +02:00
Markus Unterwaditzer
842162136a Fix nextcloud submodule URL 2016-06-16 17:23:46 +02:00
Markus Unterwaditzer
8d0b055110 Merge pull request #470 from pimutils/collections-null-fix
Kill special codepath for `null`-collection
2016-06-16 15:30:16 +02:00
Markus Unterwaditzer
c6e66dc682 Test nextcloud (#473) 2016-06-16 15:28:24 +02:00
Markus Unterwaditzer
403a683e70 Cosmetic improvements 2016-06-16 15:10:03 +02:00
Markus Unterwaditzer
8c1ae4f099 Kill special codepath for null-collection 2016-06-16 15:10:03 +02:00
Markus Unterwaditzer
5f302b0206 Version 0.11.2 2016-06-15 18:14:09 +02:00
Markus Unterwaditzer
54517b61c9 Fix typo that would break tests 2016-06-15 18:13:44 +02:00
Markus Unterwaditzer
cf82eef7b9 Version 0.11.1 2016-06-15 17:25:50 +02:00
Markus Unterwaditzer
f289437e46 Fix validation bugs for collections parameter 2016-06-15 17:17:07 +02:00
Markus Unterwaditzer
a8c79ed1fc Merge pull request #466 from pimutils/collections-null-google
Improve error for unsupported collections = null
2016-06-10 10:38:10 +02:00
Markus Unterwaditzer
2c3238e550 Merge pull request #464 from evgeni/improve-google-documentation
Improve google documentation
2016-06-10 10:36:51 +02:00
Evgeni Golov
9f5c88bece point out that CalDAV/CardDAV is different to Calendar/Contacts APIs 2016-06-10 07:43:15 +02:00
Evgeni Golov
eb2c25ee76 it has to be note:: otherweise sphinx won't render the paragraph at all (#465) 2016-06-10 00:20:24 +02:00
Markus Unterwaditzer
f892389806 Fix traceback output 2016-06-10 00:17:21 +02:00
Markus Unterwaditzer
0fb27cc391 Improve error for unsupported collections = null 2016-06-10 00:15:37 +02:00
Markus Unterwaditzer
3cb03a55e4 Fix race conditions in Google storage (#460)
Fix #456
Fix #404
2016-06-09 23:57:27 +02:00
Evgeni Golov
f3023748a7 properly quote "from a" (#463) 2016-06-09 23:09:12 +02:00
Markus Unterwaditzer
d107a1f9cc Don't show codecov status on PRs 2016-06-03 15:15:37 +02:00
Markus Unterwaditzer
1b31f1449e Slightly improved error messages 2016-05-30 23:38:43 +02:00
Markus Unterwaditzer
252f634c81 Hide tracebacks from default output 2016-05-30 23:28:10 +02:00
Markus Unterwaditzer
586f923c83 Remove outdated parameter from docs 2016-05-30 22:52:39 +02:00
Markus Unterwaditzer
b3d70a7a93 Use os.fstat wherever possible 2016-05-26 20:03:01 +02:00
Markus Unterwaditzer
d24f3835ef Replace text/icalendar with text/calendar
Fix #455
2016-05-25 19:23:25 +02:00
Markus Unterwaditzer
130c9248ba Request server info in ISSUE_TEMPLATE 2016-05-24 18:22:55 +02:00
Markus Unterwaditzer
35c46a030a Add vdirel to applications
cc @damiencassou

See https://github.com/DamienCassou/vdirel/issues/1
2016-05-24 16:39:32 +02:00
Markus Unterwaditzer
c84bab113a Update ownCloud 2016-05-24 14:19:33 +02:00
Markus Unterwaditzer
b806f1b827 Remove outdated comment 2016-05-19 20:43:16 +02:00
Markus Unterwaditzer
aa006a7c4a Version 0.11.0 2016-05-19 18:37:20 +02:00
Markus Unterwaditzer
c0aee14acf setup.py: Refer to packaging.rst 2016-05-19 18:07:29 +02:00
Markus Unterwaditzer
139182ef2a Weaken test 2016-05-13 23:59:34 +02:00
Markus Unterwaditzer
09d6aeb4b1 Update davical server 2016-05-13 22:17:19 +02:00
Markus Unterwaditzer
61dce503a3 Fix remoteStorage tests 2016-05-13 21:56:48 +02:00
Homu
36ffac8801 Auto merge of #450 - pimutils:fix-discover-test, r=untitaker
Fix defective discovery test

Found via #448
2016-05-14 04:44:15 +09:00
Markus Unterwaditzer
b5a690e9b2 Fix defective discovery test
Also split up in two testcases
2016-05-13 21:25:45 +02:00
Markus Unterwaditzer
207091f11a Stylefixes 2016-05-12 20:36:34 +02:00
Markus Unterwaditzer
2b6456e572 Fix broken Hypothesis test 2016-05-12 20:27:12 +02:00
Markus Unterwaditzer
4742ea61bc Nicer error message for InvalidResponse
See #448
2016-05-12 18:40:15 +02:00
Markus Unterwaditzer
45cea8f1f3 Fix codecov again, v2 2016-05-11 11:23:38 +02:00
Markus Unterwaditzer
89e45a54c6 Fix codecov again 2016-05-11 11:23:03 +02:00
Markus Unterwaditzer
2fd7f69479 codecov: Disable comments 2016-05-07 18:22:47 +02:00
Steve Peak
e33768757d Update codecov.yml (#445) 2016-05-07 18:20:55 +02:00
Markus Unterwaditzer
d7a527b5be Add Gentoo package
Thanks to @amynka
2016-05-07 01:24:34 +02:00
Markus Unterwaditzer
e72dc441a5 Simplify main help text 2016-05-04 21:04:20 +02:00
Markus Unterwaditzer
d16721cde8 Replace a few skips with xfails 2016-05-02 17:07:31 +02:00
Markus Unterwaditzer
fc3e823b6b Use os.environ instead of getenv
None.lower() fails too, but KeyError() is a nicer errormessage
2016-05-02 16:50:19 +02:00
Markus Unterwaditzer
d3724ebb19 Reorder tests 2016-05-02 16:43:24 +02:00
Markus Unterwaditzer
900ffceca9 Refactor test_config 2016-05-02 16:41:03 +02:00
Markus Unterwaditzer
e4c88ce84b Fix formatting 2016-05-01 21:28:17 +02:00
Markus Unterwaditzer
08b7db3478 Stylefix 2016-04-30 19:46:13 +02:00
Markus Unterwaditzer
66c6f31c8b Remove test of deprecated code
See a1532f36f6
2016-04-30 18:49:43 +02:00
Markus Unterwaditzer
a1532f36f6 Remove old code for deprecations 2016-04-29 20:33:06 +02:00
Markus Unterwaditzer
fc0eca0eb8 Another nocover branch 2016-04-29 20:27:25 +02:00
Markus Unterwaditzer
5749986b54 Don't require coverage for internal assertions 2016-04-29 20:23:02 +02:00
Markus Unterwaditzer
a79e30b0b0 Add tests about flaky etags 2016-04-29 20:22:07 +02:00
Markus Unterwaditzer
cf17ac0509 Stylefix 2016-04-29 20:17:27 +02:00
Markus Unterwaditzer
cf225cc038 Add comment 2016-04-29 20:17:01 +02:00
Markus Unterwaditzer
7418acc42f More assertions regarding read_only and sync 2016-04-29 20:14:16 +02:00
Markus Unterwaditzer
cbb1967017 Test read_only in sync 2016-04-29 20:07:27 +02:00
Markus Unterwaditzer
b9f3ca3581 Fix hypothesis metadata tests 2016-04-29 19:47:48 +02:00
Markus Unterwaditzer
96c90af1e3 Add flag about Py2 monkeypatch for tests 2016-04-29 19:04:14 +02:00
Markus Unterwaditzer
f007cacdba Add hypothesis test for metasync 2016-04-29 19:03:12 +02:00
Markus Unterwaditzer
29d7054e82 Stylefix 2016-04-28 22:12:02 +02:00
Markus Unterwaditzer
e7d73da4aa Be conservative with assume() usage 2016-04-28 21:49:39 +02:00
Markus Unterwaditzer
208c9ca787 Extra test for collection = null 2016-04-28 21:27:24 +02:00
Markus Unterwaditzer
ea17f2ac01 Show error for Python 2 users (#441)
* Show error for Python 2 users

The error can be disabled with a config option.

See #219
2016-04-28 16:44:17 +02:00
Markus Unterwaditzer
3ac486cff1 Remove absolute links within docs
Leftover from old filename CONTRIBUTING.rst
2016-04-28 01:32:25 +02:00
Markus Unterwaditzer
632b884e54 New domain for readthedocs 2016-04-28 01:30:56 +02:00
Markus Unterwaditzer
70c6349de9 Catch up in changelog 2016-04-28 00:57:54 +02:00
Markus Unterwaditzer
d06dd4ca85 Add example for metadata sync (#440)
Fix #422
2016-04-28 00:55:35 +02:00
Markus Unterwaditzer
b68bb78bfc Migrate codecov settings 2016-04-28 00:52:59 +02:00
Markus Unterwaditzer
41c59f4c47 Make discovery explicit (#439)
* Make discovery explicit

Fix #438
2016-04-27 02:17:16 +02:00
Markus Unterwaditzer
f1d03e6380 Refactor UX of discovery (#437)
* Refactor UX of discovery

- The new `--list` option for `vdirsyncer discover`, enabled by default,
  makes vdirsyncer list all collections before saving the configuration.
  It is not enabled when vdirsyncer tries to discover when invoked via
  `vdirsyncer sync`. Fix #424

- There are no duplicate collections anymore. Fix #419.

- `vdirsyncer discover` is running with one worker by default now, to
  avoid broken output. See also #404.
2016-04-27 00:35:30 +02:00
Markus Unterwaditzer
db4923c3ef Stylefixes 2016-04-26 22:44:19 +02:00
benjaminfrank
f1821f0786 Initial MacOS X launchd .plist file. (#435) 2016-04-25 21:57:15 +02:00
Markus Unterwaditzer
2beb854157 Factor out duplicate UID strategies 2016-04-25 21:48:51 +02:00
Markus Unterwaditzer
9081284f02 Stylefixes 2016-04-25 18:54:28 +02:00
Markus Unterwaditzer
8d9efc3014 Hypothesis tests for sync (#436) 2016-04-24 19:59:35 +02:00
Markus Unterwaditzer
aee99708a3 Version 0.10 2016-04-23 16:22:15 +02:00
Markus Unterwaditzer
90fa9f7f5f Fix XML creation bug 2016-04-23 14:04:46 +02:00
Markus Unterwaditzer
1674a6565a Update testservers 2016-04-23 13:58:09 +02:00
Homu
746de7fb70 Auto merge of #434 - pimutils:kill-lxml, r=untitaker
Replace LXML with stdlib XML

Just because the XML module is already there, and suits our needs as
well. DoS concerns should be irrelevant as we trust the server to that
extent.

Fix #433
2016-04-23 20:16:00 +09:00
Markus Unterwaditzer
ec2f743ffa Replace LXML with stdlib XML
Just because the XML module is already there, and suits our needs as
well. DoS concerns should be irrelevant as we trust the server to that
extent.
2016-04-22 23:08:32 +02:00
Markus Unterwaditzer
3bad8e0c78 pipsi: Use Python 3 2016-04-20 19:04:12 +02:00
Markus Unterwaditzer
d594f9fd24 Update servers 2016-04-17 23:35:35 +02:00
Markus Unterwaditzer
43c3ef6d03 Add gratipay team link to README 2016-04-14 16:25:08 +02:00
Homu
7917f2e6f4 Auto merge of #427 - pimutils:update-baikal, r=untitaker
Update Baikal to 0.4.4

None
2016-04-11 04:41:28 +09:00
Markus Unterwaditzer
ed61980000 Update Baikal to 0.4.4 2016-04-10 20:18:25 +02:00
Homu
52d4e596a4 Auto merge of #426 - pimutils:update-owncloud, r=untitaker
Update ownCloud to 9.0.1

None
2016-04-11 03:12:51 +09:00
Markus Unterwaditzer
05366cd2ff Update ownCloud to 9.0.1 2016-04-10 20:08:01 +02:00
Markus Unterwaditzer
ba4f48842e Add @marmarek to authors 2016-04-10 13:45:05 +02:00
Markus Unterwaditzer
be8df955e9 Ability to sync differently named collections with each other (#423)
* Ability to sync differently named collections

* Fixes

* Fixes

* Add example
2016-04-10 12:36:51 +02:00
Markus Unterwaditzer
777eb35898 Merge pull request #412 from pimutils/remove-google-oauth-creds
Remove default client ID for Google
2016-04-08 00:20:44 +02:00
Markus Unterwaditzer
2386f1c1bc Merge pull request #415 from pimutils/issue-414
Py2: If file doesn't exist, IOError will be raised
2016-04-08 00:20:36 +02:00
Markus Unterwaditzer
313e36646b Merge pull request #413 from pimutils/storage-init-no-defaults-bug
Fix bug in storage init errorhandler
2016-04-08 00:20:23 +02:00
Markus Unterwaditzer
46639ff65e Py2: If file doesn't exist, IOError will be raised
Fix #414
2016-04-08 00:03:03 +02:00
Markus Unterwaditzer
f4d285a066 Add link to ToS 2016-04-07 23:23:13 +02:00
Markus Unterwaditzer
374a4921b7 Fix bug in storage init errorhandler
If there are no defaults, spec.args would be sliced like
`spec.args[1:0]` which always produces an empty slice.
2016-04-07 23:22:04 +02:00
Markus Unterwaditzer
12c22f19c0 Remove default client ID for Google
Change the documentation accordingly

Fix #407
2016-04-07 23:10:00 +02:00
Homu
f8a3961de5 Auto merge of #409 - lucc:config, r=untitaker
Add a --config-file option.

None
2016-04-08 03:58:25 +09:00
Homu
089c88b6be Auto merge of #411 - pimutils:disable-radicale-dev, r=untitaker
Don't test development Radicale

None
2016-04-08 02:53:53 +09:00
Markus Unterwaditzer
7a5241101e Don't test development Radicale 2016-04-07 19:52:25 +02:00
Lucas Hoffmann
10cc4b1a16 Add a --config option. 2016-04-07 18:48:01 +02:00
Markus Unterwaditzer
69b88dd0c0 Merge pull request #406 from pimutils/fix-google2
More bugfixes for Google
2016-04-06 18:47:20 +02:00
Markus Unterwaditzer
b3c1b00f1b Refactor handle_storage_init_error 2016-04-06 15:22:09 +02:00
Markus Unterwaditzer
2fb7a8d99f More bugfixes for Google 2016-04-06 15:22:09 +02:00
Markus Unterwaditzer
020f67ec26 Bugfixes for Google storage
Bugfixes for Google storage
2016-04-06 14:23:42 +02:00
Markus Unterwaditzer
50fc582aa3 Bugfixes for Google storage
- the tilde wouldn't be expanded to $HOME for token_file value, causing
  a crash

- due to wrong type signatures, vdirsyncer's storage init code would
  guess that the instance_name parameter was not allowed, and that that
  lead to the crash
2016-04-05 18:38:23 +02:00
Markus Unterwaditzer
d034c6b67f Split table of contents into three categories
* Split table of contents into three categories

* Add info about issue tracker and waffle.io

Fix #388
2016-04-04 23:24:06 +02:00
Homu
f8a2b109a9 Auto merge of #401 - pimutils:count-failed-tasks, r=untitaker
CLI worker: Show how many tasks failed

Fix #398
2016-04-04 06:39:06 +09:00
Markus Unterwaditzer
8134313390 CLI worker: Show how many tasks failed
Fix #398
2016-04-03 23:36:49 +02:00
Homu
45389f87d9 Auto merge of #400 - pimutils:not-implemented-discovery, r=untitaker
Nicer output for unsupported discovery

Fix #347
2016-04-03 06:49:52 +09:00
Markus Unterwaditzer
3b9ef7a16b Nicer output for unsupported discovery
Fix #347
2016-04-02 23:12:55 +02:00
Homu
77d5a7d655 Auto merge of #399 - pimutils:google, r=untitaker
Google contacts and calendar

- [x] Proper documentation
- [x] With the refactor, `get_storage_init_args` now misses a lot of arguments for all DAV and Google storage types

Fix #8
2016-04-03 05:56:14 +09:00
Markus Unterwaditzer
6e10666ab1 Add changelog 2016-04-02 22:56:01 +02:00
Markus Unterwaditzer
2888757e1b Refactor Google support into own storage types 2016-04-02 21:14:17 +02:00
Markus Unterwaditzer
eca9faad16 Make DavSession subclassable 2016-04-02 20:51:31 +02:00
Marek Marczykowski
6d8db949fa Initial OAuth2 (Google variant) support for dav storage
This commits adds 'oauth2_google' authentication mechanism to dav
storage driver.
2016-04-02 20:51:11 +02:00
Markus Unterwaditzer
4cb7e6c1f5 Don't test Radicale under Python 2 2016-04-01 23:47:36 +02:00
Markus Unterwaditzer
b501a86081 Fix formatting in docs 2016-03-30 23:13:12 +02:00
Markus Unterwaditzer
0ee39c7e0a cli: Remove outdated reference to PAIRS 2016-03-28 12:21:04 +02:00
Homu
15de73d8fc Auto merge of #396 - pimutils:fix-empty-sync, r=untitaker
Fix hangup on no-op sync

None
2016-03-28 03:37:04 +09:00
Markus Unterwaditzer
bd6bca6540 Fix hangup on no-op sync
Fix #395
2016-03-26 22:05:47 +01:00
Markus Unterwaditzer
391f193eae Rename test_main to test_sync 2016-03-26 21:37:22 +01:00
Markus Unterwaditzer
7f54fb5dd9 Add PayPal link as well 2016-03-24 17:19:20 +01:00
Markus Unterwaditzer
862bf24e6b The dumbest bug fix 2016-03-22 22:47:16 +01:00
Markus Unterwaditzer
0195f85af0 Stylefix 2016-03-22 22:43:46 +01:00
Markus Unterwaditzer
b73c0908d0 Version 0.9.3 2016-03-22 20:52:36 +01:00
Markus Unterwaditzer
3e327ad9f5 Remove entry-point test
I thought it was common practice to run testsuites post-install.
Apparently this isn't the case with Archlinux, which executes `check`
between `build` and `install`.

Fix #393
2016-03-22 20:49:30 +01:00
Markus Unterwaditzer
0788277a2f More changelog entries 2016-03-20 15:08:01 +01:00
Homu
307a368917 Auto merge of #391 - pimutils:split-recurring-events, r=untitaker
Split recurring events properly

Previously we moved each VEVENT into its own Item, now we group by UID,
if one exists.
2016-03-20 22:55:11 +09:00
Markus Unterwaditzer
7ce0fb958f Split recurring events properly
Previously we moved each VEVENT into its own Item, now we group by UID,
if one exists.
2016-03-20 14:16:52 +01:00
Markus Unterwaditzer
68f052b7c2 Add waffle.io badge 2016-03-19 23:51:48 +01:00
Markus Unterwaditzer
b93bcf0ba8 New IRC channel 2016-03-16 00:26:48 +01:00
Markus Unterwaditzer
c855be0015 Update submodules 2016-03-15 21:25:34 +01:00
Markus Unterwaditzer
63fc62afda We init our submodules ourselves 2016-03-15 21:09:01 +01:00
Markus Unterwaditzer
085cd692a7 Update submodules 2016-03-15 20:57:17 +01:00
Markus Unterwaditzer
3fd1098ca5 docs: Reformat packaging.rst 2016-03-15 20:42:43 +01:00
Markus Unterwaditzer
89f9b35e1c docs: Annotate commands in contributing.rst 2016-03-15 20:36:57 +01:00
Markus Unterwaditzer
071f3e06f4 Leftover legacy link 2016-03-15 15:38:58 +01:00
Markus Unterwaditzer
b726364b93 Replace all instances of untitaker with pimutils 2016-03-15 15:36:40 +01:00
Markus Unterwaditzer
9f48f7d3b2 Merge pull request #387 from untitaker/ci-refactor
Minimal PR build, v2
2016-03-14 19:06:21 +01:00
Markus Unterwaditzer
0ac1688518 make style: Ignore whitespace changes
For some godforsaken reason different line endings are emitted in
Travis.
2016-03-14 17:57:07 +01:00
Markus Unterwaditzer
b197592774 Minimal PR build again 2016-03-14 16:35:59 +01:00
Markus Unterwaditzer
87560481d6 Update davical module 2016-03-14 15:32:59 +01:00
Markus Unterwaditzer
44721f18dd Merge pull request #385 from DamienCassou/patch-1
Fix Makefile rule to reference install-test
2016-03-14 11:04:00 +01:00
Damien Cassou
e5e1f42013 Fix Makefile rule to reference install-test 2016-03-14 07:46:40 +01:00
Markus Unterwaditzer
dac6295376 Merge pull request #384 from untitaker/open-graphical-browser-hotfix
Fix broken test for webbrowser internals
2016-03-13 20:54:46 +01:00
Markus Unterwaditzer
c95fa8fc3c Version 0.9.2 2016-03-13 20:54:26 +01:00
Markus Unterwaditzer
0e7fa2ed62 Fix broken test for webbrowser internals
List may be empty if running in minimal environment.
2016-03-13 20:38:00 +01:00
Markus Unterwaditzer
d8854294e1 Stylefix 2016-03-13 20:23:19 +01:00
Markus Unterwaditzer
c9aada3012 Also test master 2016-03-13 20:23:00 +01:00
Markus Unterwaditzer
108c375f39 Version 0.9.1 2016-03-13 19:03:20 +01:00
Homu
a2ec405fd0 Auto merge of #380 - untitaker:os-x, r=untitaker
Test against OS X (PR)

Fixes #379
2016-03-13 05:35:48 +09:00
Markus Unterwaditzer
0d0902cc48 Test OS X 2016-03-12 21:34:45 +01:00
Homu
f9375eaa82 Auto merge of #378 - untitaker:server-submodules, r=untitaker
Add servers as submodules

Fix #377
2016-03-11 20:14:21 +09:00
Markus Unterwaditzer
7f124494ee Exclude servers from flake8 2016-03-11 12:14:10 +01:00
Homu
163da71453 Auto merge of #373 - untitaker:hypothesis-tolerate-ci-slowness, r=untitaker
Testing: Tolerate slowness in CI

None
2016-03-11 18:39:30 +09:00
Homu
f61d19bf5f Auto merge of #376 - untitaker:branches-whitelist, r=untitaker
Build only branches on whitelist

None
2016-03-11 10:59:37 +09:00
Markus Unterwaditzer
89923a0e72 Add helper target for setting submodules to SSH URLs 2016-03-10 23:17:07 +01:00
Markus Unterwaditzer
6a2dc53db9 Add servers as submodules 2016-03-10 22:50:11 +01:00
Markus Unterwaditzer
0c22a2fe1e Build only auto branch 2016-03-10 22:17:04 +01:00
Markus Unterwaditzer
b346e2ea07 Merge pull request #374 from untitaker/dev-click
Test against dev-click too
2016-03-10 21:07:17 +01:00
Markus Unterwaditzer
88df14a724 Testing: Tolerate slowness in CI 2016-03-10 13:46:44 +01:00
Markus Unterwaditzer
130edac67e Test against dev-click too 2016-03-10 13:38:57 +01:00
Markus Unterwaditzer
d7dace2a26 Merge pull request #371 from untitaker/remove-hardcoded-link
Remove hardcoded link
2016-03-10 12:14:22 +01:00
Markus Unterwaditzer
ad304d1435 Remove hardcoded link 2016-03-10 12:14:13 +01:00
Markus Unterwaditzer
4e28c07b02 Merge pull request #370 from hobarrera/logging-cleanup
Clean up logging usage
2016-03-10 12:13:15 +01:00
Markus Unterwaditzer
55914bd575 Merge pull request #372 from untitaker/test-open-graphical-browser
Add tests for open_graphical_browser
2016-03-10 12:13:00 +01:00
Hugo Osvaldo Barrera
552ecbee16 Delete unused function 2016-03-09 20:40:55 -03:00
Hugo Osvaldo Barrera
4467d3e2de Clean up logging usage 2016-03-09 20:40:52 -03:00
Markus Unterwaditzer
376d6fc70b Add tests for open_graphical_browser
Fix #312
2016-03-10 00:03:22 +01:00
Markus Unterwaditzer
9862eb9865 Merge pull request #368 from untitaker/remove-owncloud-xfail
Remove owncloud xfails
2016-03-09 20:50:25 +01:00
Markus Unterwaditzer
0cba8eb816 Remove outdated reference to https://github.com/owncloud/core/issues/18409 2016-03-09 16:00:06 +01:00
Markus Unterwaditzer
baa82846c0 Remove ownCloud skip for multiget crash
Ref https://github.com/owncloudarchive/calendar/issues/935
2016-03-09 15:53:47 +01:00
Markus Unterwaditzer
1f190e69ff Remove ownCloud skip for metadata glitch
Ref https://github.com/owncloud/core/issues/18409
2016-03-09 15:52:42 +01:00
Markus Unterwaditzer
a3a1898ef4 Merge pull request #367 from untitaker/remove-xprocess-test-requirement
Remove pytest-xprocess from test requirements
2016-03-09 13:38:46 +01:00
Markus Unterwaditzer
4ff0680092 Merge pull request #366 from untitaker/remove-baikal-xfail
Remove old Baikal xfails
2016-03-09 12:59:13 +01:00
Markus Unterwaditzer
393387fe46 Remove pytest-xprocess from test requirements
It is only required by ownCloud and Baikal testservers.
2016-03-09 00:01:06 +01:00
Markus Unterwaditzer
66bd52244d Remove old Baikal xfails
Ref #160
Ref https://github.com/fruux/sabre-dav/issues/422
2016-03-08 21:27:45 +01:00
Markus Unterwaditzer
acac746d2d Merge pull request #365 from untitaker/fix-358-again
Refactor metadata None values
2016-03-07 14:35:10 +01:00
Markus Unterwaditzer
75a9987ec2 Hypothesis: Blacklist surrogates 2016-03-06 22:50:55 +01:00
Markus Unterwaditzer
23ea0e203f Refactor metadata None values
This fixes #358 again, in a different way.
2016-03-06 21:13:50 +01:00
Markus Unterwaditzer
6b9d7b074a Stylefix 2016-03-05 21:05:36 +01:00
Markus Unterwaditzer
949c568852 Pin requests>=2.4.1 and remove weird version check 2016-03-05 20:20:22 +01:00
Markus Unterwaditzer
81b56ac5d3 Soften assertion for Python 2
I really don't care about correctness anymore, this madness will go away
once we ditch Py2.
2016-03-05 20:20:22 +01:00
Markus Unterwaditzer
017495935f Pin requests-toolbelt back to >=0.4.0 2016-03-05 20:20:22 +01:00
Markus Unterwaditzer
c049f17928 Merge pull request #361 from hobarrera/generic-ci
Replace instances of envvar TRAVIS with CI
2016-03-04 23:49:34 +01:00
Hugo Osvaldo Barrera
bac0966814 Replace instances of envvar TRAVIS with CI 2016-03-04 12:32:50 -03:00
Markus Unterwaditzer
cfe53f4a8b Mention packaging guidelines in changelog 2016-03-04 15:09:12 +01:00
Markus Unterwaditzer
88547294a7 Merge pull request #354 from untitaker/packaging-guidelines
Add packaging guidelines
2016-03-04 15:08:16 +01:00
Markus Unterwaditzer
13af5ffbaf Replace CI with TRAVIS 2016-03-04 15:07:55 +01:00
Markus Unterwaditzer
e244eecc52 Stylefixes 2016-03-04 15:07:55 +01:00
Markus Unterwaditzer
7ad2af7063 packaging.rst: Add note about DETERMINISTIC_TESTS 2016-03-04 15:07:55 +01:00
Hugo Osvaldo Barrera
1ede6884b7 Allow running deterministic tests 2016-03-04 15:07:55 +01:00
Markus Unterwaditzer
c8c4409321 Just use a normal loop 2016-03-04 15:07:55 +01:00
Markus Unterwaditzer
fe5ac51231 Use new minimal_requirements command in Makefile 2016-03-04 15:07:55 +01:00
Markus Unterwaditzer
dd48ac05c9 Rename setup.py requirements cmd 2016-03-04 15:07:55 +01:00
Hugo Osvaldo Barrera
8a7ac52ee7 Implement command to print minimal requirements 2016-03-04 15:07:55 +01:00
Markus Unterwaditzer
48a649ee8c Fix up requirements=minimal 2016-03-04 15:07:55 +01:00
Markus Unterwaditzer
cd07d7fc68 Add test for proper dependencies 2016-03-04 15:07:55 +01:00
Markus Unterwaditzer
c7e6ca20e4 Add packaging guidelines 2016-03-04 15:07:55 +01:00
Markus Unterwaditzer
e04511f348 Merge pull request #359 from untitaker/strip-metadata-from-whitespace
metasync: Strip whitespace from values
2016-03-04 15:06:24 +01:00
Markus Unterwaditzer
52489f471f Add changelog 2016-03-04 15:06:00 +01:00
Markus Unterwaditzer
e725df4747 metasync: Strip whitespace from values
Fix #358
2016-03-04 15:06:00 +01:00
Markus Unterwaditzer
325831049b Reshuffle docs again 2016-03-04 14:58:55 +01:00
Markus Unterwaditzer
07078fa06b Add CONTRIBUTING link in README 2016-03-04 14:49:49 +01:00
Markus Unterwaditzer
5b1128611e Improve travis.yml stylecheck 2016-03-04 14:28:09 +01:00
Markus Unterwaditzer
3eee5a55a1 Hypothesis: Use more idiomatic filter instead of return 2016-03-04 12:38:17 +01:00
Markus Unterwaditzer
54fa46ffae Merge pull request #351 from untitaker/hypothesis-tests
More hypothesis tests
2016-03-04 08:27:25 +01:00
Markus Unterwaditzer
dec27d3b17 More hypothesis tests 2016-03-02 15:59:46 +01:00
Markus Unterwaditzer
767566b48b Merge pull request #353 from hobarrera/conflicts-link
Fix broken link to conflict documentation
2016-03-02 15:54:37 +01:00
Hugo Osvaldo Barrera
dc8d787d50 Fix broken link to conflict documentation 2016-03-02 03:16:01 -03:00
Markus Unterwaditzer
eb396c12cc Fix NameError
See geier/khal#366
2016-03-01 16:54:56 +01:00
Markus Unterwaditzer
a25fd354d9 Remove unnecessary teardown 2016-03-01 14:57:34 +01:00
Markus Unterwaditzer
649576eeb2 Add license note 2016-02-29 17:48:50 +01:00
Markus Unterwaditzer
f9854b9077 Merge pull request #346 from untitaker/fix-coerce-native
Fix coerce_native
2016-02-29 00:06:20 +01:00
Markus Unterwaditzer
768cebe0e1 Fix coerce_native
See #344
2016-02-28 19:08:18 +01:00
Markus Unterwaditzer
8b13a932b8 Merge pull request #348 from hobarrera/nonexistant-pair-message
Add prettier message when syncing inexistent pair
2016-02-28 19:04:53 +01:00
Hugo Osvaldo Barrera
f9c1bcb9a1 Add test when syncing inexistent pair 2016-02-28 07:13:12 -03:00
Hugo Osvaldo Barrera
c66432e2ee Add prettier message when syncing inexistent pair 2016-02-28 07:13:05 -03:00
Markus Unterwaditzer
0162a0c4b6 Prepare changelog for 0.9.1 2016-02-27 20:35:46 +01:00
Markus Unterwaditzer
95a7fc9789 Merge pull request #340 from untitaker/better-coverage
Better coverage
2016-02-27 20:30:03 +01:00
Markus Unterwaditzer
7d60c05b2b filesystem: missing metadata is handled correctly 2016-02-26 16:39:37 +01:00
Markus Unterwaditzer
8a6ad410da Tests for fetchparams 2016-02-26 16:39:37 +01:00
Markus Unterwaditzer
f3c459eb7d 100% coverage for vdirsyncer.__init__ 2016-02-26 16:39:37 +01:00
Markus Unterwaditzer
5300e6816b 100% coverage for metasync 2016-02-26 16:39:37 +01:00
Markus Unterwaditzer
d1d47256ab Fix stylization in tutorial 2016-02-25 23:04:02 +01:00
Markus Unterwaditzer
46b9168440 Merge pull request #342 from untitaker/issue-template
Add issue template
2016-02-25 22:28:09 +01:00
Markus Unterwaditzer
4c6d3a3b89 Add issue template 2016-02-25 22:27:42 +01:00
Markus Unterwaditzer
9c1c4f92de Merge pull request #339 from untitaker/docs-fix-metadata-term
Docs: Fix ambiguous use of term metadata
2016-02-25 22:01:32 +01:00
Markus Unterwaditzer
00c0d64632 Docs: Fix ambiguous use of term metadata 2016-02-24 16:49:22 +01:00
Markus Unterwaditzer
5e8d422e9a Revamp donations 2016-02-21 14:58:58 +01:00
Markus Unterwaditzer
532f63a227 Re-add vdir to toctree 2016-02-21 14:31:29 +01:00
Markus Unterwaditzer
85a4b4da6d Fix makefile 2016-02-21 13:44:46 +01:00
Markus Unterwaditzer
53dc69262e Merge pull request #338 from untitaker/irc-channel
Add IRC channel to docs
2016-02-20 21:56:18 +01:00
Markus Unterwaditzer
452cec1778 Restructure docs 2016-02-20 21:56:02 +01:00
Markus Unterwaditzer
36d8b535d7 Update README to deduplicate docs 2016-02-20 21:48:08 +01:00
Markus Unterwaditzer
865a2df854 Add IRC channel to docs 2016-02-20 21:45:16 +01:00
Markus Unterwaditzer
b89b890769 Install development hypothesis and pytest 2016-02-20 21:45:03 +01:00
Markus Unterwaditzer
2c3af41fa6 Merge pull request #336 from untitaker/fix-py33-hypothesis
Install enum for Py33
2016-02-18 22:12:18 +01:00
Markus Unterwaditzer
ecadc430b8 Install enum for Py33 2016-02-18 20:52:10 +01:00
Markus Unterwaditzer
f81f248dde Stylefix 2016-02-17 19:51:18 +01:00
Markus Unterwaditzer
6e9e856aae Better comments 2016-02-16 23:05:00 +01:00
Markus Unterwaditzer
f2a0d07c09 Fix bug in sync if href changes 2016-02-16 22:59:07 +01:00
Markus Unterwaditzer
3d856749f3 Remove debug print statement
omfg
2016-02-16 21:09:05 +01:00
Markus Unterwaditzer
ebfc3182ce Update copyright notice 2016-02-16 19:08:50 +01:00
Markus Unterwaditzer
125084fcf9 Merge pull request #333 from untitaker/un-ignore-version
Remove VERSION from ignored props, more tests
2016-02-16 18:43:45 +01:00
Markus Unterwaditzer
fd3d81e925 Remove VERSION from ignored props, more tests 2016-02-16 01:37:39 +01:00
Markus Unterwaditzer
27345add6d Accomodate to new Sabre version 2016-02-15 21:57:58 +01:00
Markus Unterwaditzer
e30f71d63e Version 0.9.0 2016-02-15 15:46:04 +01:00
Markus Unterwaditzer
7ef0e992b1 Merge pull request #331 from untitaker/collection-default
Remove the default of collections to autodiscovery
2016-02-15 15:45:20 +01:00
Markus Unterwaditzer
727ce250cf Remove the default of collections to autodiscovery
See #328
2016-02-12 23:00:07 +01:00
Markus Unterwaditzer
3c9ef726df Merge pull request #330 from untitaker/kill-clierror
Merge CliError into UserError
2016-02-10 16:03:27 +01:00
Markus Unterwaditzer
be4baba19e Merge CliError into UserError 2016-02-10 15:09:25 +01:00
Markus Unterwaditzer
9e8b5f2dad Makefile: Remove obsolete information 2016-02-04 21:47:56 +01:00
Markus Unterwaditzer
5c769fd63d Merge pull request #327 from untitaker/rewrite-when-docs
Rewrite 'When' page
2016-02-02 16:15:28 +01:00
Markus Unterwaditzer
15c8ceee5f Rewrite 'When' page 2016-02-01 22:48:20 +01:00
Markus Unterwaditzer
20ac606132 Version 0.8.1 2016-01-30 21:11:43 +01:00
Markus Unterwaditzer
fcb732874d Show UserError without traceback 2016-01-30 19:24:06 +01:00
Markus Unterwaditzer
9bd490f402 Add XXX to keyring special-casing 2016-01-30 18:54:22 +01:00
Markus Unterwaditzer
d30b4752db Fix error messages for unknown fetchparam strategy
See #326
2016-01-30 18:51:27 +01:00
Markus Unterwaditzer
6c7b6f47b1 Version 0.8.0 2016-01-28 00:00:30 +01:00
Markus Unterwaditzer
b72303b823 Add comments for #298 2016-01-26 23:53:40 +01:00
Markus Unterwaditzer
ef8c638f41 Changelog for #324 2016-01-25 19:43:39 +01:00
Markus Unterwaditzer
d4a55f55b8 Revert "Pin pytest"
This reverts commit c54aaeb56e.

Fix #325
2016-01-25 18:35:30 +01:00
Markus Unterwaditzer
4212797531 Merge pull request #324 from untitaker/issue219-warn-on-py2
Warn when running under Python 2
2016-01-24 19:35:52 +01:00
Markus Unterwaditzer
b12660f1a8 Warn when running under Python 2
See #219
2016-01-24 19:35:37 +01:00
Markus Unterwaditzer
c54aaeb56e Pin pytest
See #325
2016-01-24 13:22:15 +01:00
Markus Unterwaditzer
0d88a6b3ab Merge pull request #322 from lfam/guix-package
Mention GNU Guix package
2016-01-17 19:07:19 +01:00
lfam
6d01161a05 Mention GNU Guix package
* docs/tutorial.rst (Installation): Add link to GNU Guix package.
2016-01-16 19:27:49 -05:00
Markus Unterwaditzer
3a3b6ee7ee Remove keyring support 2016-01-16 23:29:14 +01:00
Markus Unterwaditzer
7583be5826 Document that SHA256 fingerprints already work
Fix #321
2016-01-15 21:37:45 +01:00
Markus Unterwaditzer
a87ab770f8 More stylefixes 2016-01-14 18:46:50 +01:00
Markus Unterwaditzer
893f29dbaf Flake8 fixes 2016-01-14 02:51:22 +01:00
Markus Unterwaditzer
196f9c858a Some extra properties to ignore
See #318
2016-01-10 20:53:38 +01:00
Markus Unterwaditzer
d6787892e8 More Py2 hacks 2016-01-10 20:41:28 +01:00
Markus Unterwaditzer
7646222bc7 Work around massive string type inconsistency
See #315
2016-01-10 04:51:37 +01:00
Markus Unterwaditzer
2957a0dc41 Bring back the old formatting 2016-01-10 02:40:01 +01:00
Markus Unterwaditzer
129c9305f7 More safety checks for #315 2016-01-10 02:34:26 +01:00
Markus Unterwaditzer
3b9cce2128 Merge pull request #317 from untitaker/issue315
Introduce hypothesis for testing unicode
2016-01-10 02:24:57 +01:00
Markus Unterwaditzer
d8964660f8 Introduce hypothesis into codebase 2016-01-10 02:24:48 +01:00
Markus Unterwaditzer
12c87df092 Also ignore pyc in server directory 2016-01-08 22:21:26 +01:00
Markus Unterwaditzer
99f5e51ab6 Tutorial reformatting 2015-12-31 16:26:24 +01:00
Markus Unterwaditzer
8b57abaf44 Version 0.7.5 2015-12-28 17:55:20 +01:00
Markus Unterwaditzer
ce5276fba9 Stylefix 2015-12-27 23:41:00 +01:00
Markus Unterwaditzer
4fe6d59d1f Changelog for e8dbe9 2015-12-27 23:39:56 +01:00
Markus Unterwaditzer
4e8dbe9598 Only pin down lxml version for PyPy 2015-12-27 23:38:02 +01:00
Markus Unterwaditzer
c0f773214f Bugfix: open_graphical_browser opens CLI browsers 2015-12-25 21:06:55 +01:00
Markus Unterwaditzer
bb4e7b2c0e Version 0.7.4 2015-12-22 18:41:14 +01:00
Markus Unterwaditzer
7290321151 Merge pull request #310 from untitaker/mysteryshack
Test mysteryshack
2015-12-21 17:20:29 +01:00
Markus Unterwaditzer
54620c31ed Annotate version requirements 2015-12-21 00:15:25 +01:00
Markus Unterwaditzer
054a0f8cd2 Install remotestorage extra in travis 2015-12-21 00:10:55 +01:00
Markus Unterwaditzer
435b25fbca Test mysteryshack
https://github.com/untitaker/mysteryshack

This is the first remoteStorage server to be tested in Travis.

I already started testing reStore (https://github.com/jcoglan/restore),
but stopped the experiments because the server is unmaintained.
2015-12-20 22:29:24 +01:00
Markus Unterwaditzer
51abf452a1 Fix up urlencoding of remotestorage 2015-12-20 22:18:29 +01:00
Markus Unterwaditzer
731d15ebc9 Merge pull request #309 from untitaker/codecov
Use codecov instead of coveralls
2015-12-19 20:10:32 +01:00
Markus Unterwaditzer
746e1bfccf Use codecov instead of coveralls 2015-12-19 20:10:11 +01:00
Markus Unterwaditzer
b828685386 Merge pull request #307 from untitaker/fix-builds
Fix builds
2015-12-18 21:08:53 +01:00
Markus Unterwaditzer
4970c7ed78 Unfuck pypy builds 2015-12-18 21:08:36 +01:00
Markus Unterwaditzer
709377561f Release date is wrong 2015-12-18 21:08:36 +01:00
Markus Unterwaditzer
2c600c96e5 Require at least lxml==3.1 2015-12-18 21:08:35 +01:00
Markus Unterwaditzer
563f9c9d34 Re-add minimal requirements build
Testing older lxml against radicale
2015-12-18 21:08:11 +01:00
Markus Unterwaditzer
b96ace761b Merge pull request #308 from untitaker/davical-testserver
Add davical tests to Travis
2015-12-18 18:49:08 +01:00
Markus Unterwaditzer
16f0c033c2 Bugfix: Pass encoding for urlparse hack 2015-12-18 17:31:12 +01:00
Markus Unterwaditzer
8104a91769 Add davical tests to Travis 2015-12-18 15:06:54 +01:00
Markus Unterwaditzer
359a25e702 Merge pull request #306 from untitaker/debian-detector
Detect Debian-related problems and abort.
2015-12-17 14:34:20 +01:00
Markus Unterwaditzer
0aeb599e75 Exclude buggy requests version 2015-12-17 14:13:20 +01:00
Markus Unterwaditzer
ae4049ea97 Detect Debian-related problems and abort. 2015-12-17 14:07:58 +01:00
Markus Unterwaditzer
2782186421 Merge pull request #305 from untitaker/build-improvements
Improve builds
2015-12-17 14:06:28 +01:00
Markus Unterwaditzer
7e9df3dee6 Improve builds 2015-12-17 05:13:44 +01:00
Markus Unterwaditzer
cdc026ed3d Add changelogs for next version 2015-12-16 15:09:40 +01:00
Markus Unterwaditzer
f876460d35 Stylefix 2015-12-13 17:27:42 +01:00
Markus Unterwaditzer
ead85992d7 Open only once 2015-12-13 16:47:31 +01:00
Markus Unterwaditzer
c143ea4686 Merge pull request #303 from JocelynDelalande/patch-1
Fix typo on collection discovery doc
2015-12-13 15:17:38 +01:00
JocelynDelalande
0a9a04eabd Fix typo on collection discovery doc
(the example from the doc crashes on setting validation)
2015-12-13 14:45:34 +01:00
Markus Unterwaditzer
c739bbfcac vobject: Add basic error display for broken items
See #300
2015-12-13 01:53:03 +01:00
Markus Unterwaditzer
d63b63f7f9 Merge pull request #302 from geier/master
improve doc on keyring usage
2015-12-13 01:49:54 +01:00
Markus Unterwaditzer
04f06b69f0 fetchparams: Fail on empty values
See #302
2015-12-13 01:47:49 +01:00
Markus Unterwaditzer
0044a7af74 Use warnings consistently 2015-12-13 01:34:22 +01:00
Christian Geier
2fd4e24a58 improve doc on keyring usage 2015-12-12 15:40:16 +01:00
Markus Unterwaditzer
6b5cd035da Massively improve doc refs
Fix #243
2015-12-06 21:10:02 +01:00
Markus Unterwaditzer
abeb30a48a Add Known Problems to CONTRIBUTING 2015-12-05 18:41:01 +01:00
Markus Unterwaditzer
ce6653e506 Fix readme 2015-11-28 21:59:35 +01:00
Markus Unterwaditzer
53bf33dd56 Open URLs automatically during OAuth 2015-11-28 21:56:56 +01:00
Markus Unterwaditzer
2f3b2cb4f1 Open OAuth URL automatically 2015-11-28 21:56:56 +01:00
Markus Unterwaditzer
e3e5b3cde4 Merge pull request #299 from untitaker/travis-pypy-fix
Use older lxml because of Travis
2015-11-28 21:26:50 +01:00
Markus Unterwaditzer
fa2b5df05c Use older lxml because of Travis
See https://github.com/travis-ci/travis-ci/issues/5130

Meta: https://github.com/untitaker/vdirsyncer/issues/298
2015-11-28 20:47:04 +01:00
Markus Unterwaditzer
0fe2f70769 Selling out 2015-11-28 18:58:58 +01:00
Markus Unterwaditzer
cb1d1c2558 Remove Gratipay button 2015-11-28 16:24:12 +01:00
Markus Unterwaditzer
211ff0e889 Stylefixes 2015-11-28 16:08:17 +01:00
Markus Unterwaditzer
5f80b9f3f6 Fix testcase 2015-11-28 16:07:40 +01:00
Markus Unterwaditzer
b694c3f60c Add testcase for bogus etag changes 2015-11-28 16:05:22 +01:00
Markus Unterwaditzer
1d5216f2a3 Store item hashes in status, use them to detect bogus etag changes
Fix #257
2015-11-28 15:55:40 +01:00
Markus Unterwaditzer
b144ae1701 Restructure status layout for more flexibility 2015-11-28 15:41:37 +01:00
Markus Unterwaditzer
779ff094bb Fix #295 2015-11-24 23:34:56 +01:00
Markus Unterwaditzer
e5e81d5715 Loosen up equality check in conflict_res 2015-11-20 13:28:29 +01:00
Markus Unterwaditzer
3efca22207 Stylefix 2015-11-13 23:57:07 +01:00
Markus Unterwaditzer
ed22764921 Fix bug during prefetch
The idea that prefetching isn't necessary if the other storage can't be
written to is wrong, we still need to prefetch for UID-matching
2015-11-13 23:00:59 +01:00
Markus Unterwaditzer
b7542fb536 Avoid daemon threads
See #291
2015-11-06 18:09:54 +01:00
Markus Unterwaditzer
20e04e6bff Add more pkg links 2015-11-06 00:00:29 +01:00
Markus Unterwaditzer
d4cdddd72a Fixup 2015-11-05 23:52:48 +01:00
Markus Unterwaditzer
546842896d Better error message for malformed items
See #290
2015-11-05 23:50:19 +01:00
Markus Unterwaditzer
ffadca3553 Version 0.7.3 2015-11-05 16:46:03 +01:00
Markus Unterwaditzer
5616f0f197 stylefixes 2015-11-05 16:01:03 +01:00
Markus Unterwaditzer
86bf8ccffa Make requests-oauthlib actually optional 2015-11-05 15:51:48 +01:00
Markus Unterwaditzer
ed3ffcfdee Version 0.7.2 2015-11-05 15:43:33 +01:00
Markus Unterwaditzer
4602df47aa Fix formatting bug 2015-11-05 15:42:28 +01:00
Markus Unterwaditzer
2775dafffd Version 0.7.1 2015-11-05 15:39:08 +01:00
Markus Unterwaditzer
f74b6ac78e Use setuptools extras instead of requiring user to manually specify deps 2015-11-05 15:36:25 +01:00
Markus Unterwaditzer
b5b6788a3b Refactor error logging a bit
Fix #286
2015-11-05 15:29:00 +01:00
Markus Unterwaditzer
0f5bce333e Merge branch 'remotestorage' 2015-11-05 00:13:02 +01:00
Markus Unterwaditzer
d2eeaf86ee Add docs 2015-11-05 00:12:55 +01:00
Markus Unterwaditzer
82410429ba Disable restore tests 2015-11-05 00:01:41 +01:00
Markus Unterwaditzer
f2edf89543 Refine travis file 2015-11-05 00:00:18 +01:00
Markus Unterwaditzer
5050f4663d Adjust dependencies 2015-11-05 00:00:18 +01:00
Markus Unterwaditzer
87baac535d Add tests 2015-11-05 00:00:18 +01:00
Markus Unterwaditzer
6ceeb99f4a remoteStorage implementation 2015-11-05 00:00:18 +01:00
Markus Unterwaditzer
3627c6e810 Add example to owncloud docs 2015-10-30 20:15:37 +01:00
Markus Unterwaditzer
c090aaa0fe Improve StorageEmpty message 2015-10-30 20:13:37 +01:00
Markus Unterwaditzer
98111e7625 Add helpful command to fingerprint docs 2015-10-30 20:11:39 +01:00
Markus Unterwaditzer
130a5a6cc2 Fix deadlock in vdirsyncer discover 2015-10-30 19:21:02 +01:00
Markus Unterwaditzer
59078f05da Also fetchparams for repair 2015-10-30 17:25:32 +01:00
Markus Unterwaditzer
4ffce4ef12 Remove last traces of password_command 2015-10-28 16:43:40 +01:00
Markus Unterwaditzer
296c216bae Version 0.7.0 2015-10-27 18:53:32 +01:00
Markus Unterwaditzer
21b1bafc48 Add prompt strategy 2015-10-04 13:30:43 +02:00
Markus Unterwaditzer
d5254081f8 Add locks around password fetching 2015-10-03 19:27:16 +02:00
Markus Unterwaditzer
f43ef436b7 Don't change pwd for next loop run 2015-09-24 17:53:16 +02:00
Markus Unterwaditzer
5f682cadb9 Make server config management generic 2015-09-24 17:01:23 +02:00
Markus Unterwaditzer
0d3e274c4f Also include skip servertype in pkg 2015-09-23 18:25:34 +02:00
Markus Unterwaditzer
7a945e3721 Work around utter disregard of semver 2015-09-22 19:46:06 +02:00
Markus Unterwaditzer
611ceac847 Add Python 3.5 to travis 2015-09-22 19:46:06 +02:00
Markus Unterwaditzer
13925ed3d5 Extra asserts 2015-09-22 17:36:34 +02:00
Markus Unterwaditzer
89119f0cda Fix inaccuracy of Makefile 2015-09-22 16:03:36 +02:00
Markus Unterwaditzer
86d35c6d69 Merge pull request #271 from untitaker/enable-owncloud
Revert "xfail owncloud, #255"
2015-09-20 17:49:14 +02:00
Markus Unterwaditzer
b5e36ec3b2 Skip DAV tests on ownCloud for now 2015-09-20 02:14:30 +02:00
Markus Unterwaditzer
138c8f00a0 Revamp tests once again 2015-09-20 01:59:28 +02:00
Markus Unterwaditzer
22ce8cf7a4 Add bountysource shield 2015-09-20 00:19:02 +02:00
Markus Unterwaditzer
3b501b16ac Make make less stupid 2015-09-19 23:01:40 +02:00
Markus Unterwaditzer
3adb33dc8c Avoid crash when no defaults 2015-09-19 23:01:01 +02:00
Markus Unterwaditzer
670ebc0d9f Fix up docs target 2015-09-19 23:00:19 +02:00
Markus Unterwaditzer
bcd1bfdc62 Fix up build scripts 2015-09-19 22:58:32 +02:00
Markus Unterwaditzer
f0c1898265 Loosen up etag warning 2015-09-18 20:30:09 +02:00
Markus Unterwaditzer
e303c907ae Catch more IdentConflicts 2015-09-18 19:36:34 +02:00
Markus Unterwaditzer
029f5e3eee Just skip meta tests for ownCloud for now 2015-09-17 11:41:24 +02:00
Markus Unterwaditzer
dab6388cc7 Revert "xfail owncloud, #255"
This reverts commit 565ef2e96e.
2015-09-17 11:34:03 +02:00
Markus Unterwaditzer
21fb9f43ae Always coerce to unicode strings
Fix for #268
2015-09-16 22:52:52 +02:00
Markus Unterwaditzer
5506d6633d Ignore setuptools eggs 2015-09-16 22:51:18 +02:00
Markus Unterwaditzer
1c24abd4db Extend testsuite for DAV metadata 2015-09-16 22:50:54 +02:00
Markus Unterwaditzer
eb1485d99f Fix test 2015-09-12 16:42:50 +02:00
Markus Unterwaditzer
661180b138 Ignore UID when comparing items 2015-09-12 16:18:35 +02:00
Markus Unterwaditzer
d317250a8f Fix ref 2015-09-11 23:25:05 +02:00
Markus Unterwaditzer
8425984ebb Style fixes 2015-09-11 03:14:32 +02:00
Markus Unterwaditzer
41173acdf3 Shame on me, I use print for debugging 2015-09-11 03:13:10 +02:00
Markus Unterwaditzer
3a4e4218a6 New password fetching
Fix #233
2015-09-11 02:53:31 +02:00
Markus Unterwaditzer
e198326340 Revert "Add multifilesystem back"
This reverts commit 1182350af3.
2015-09-05 04:11:10 +02:00
Markus Unterwaditzer
ed0bc9b532 Fix metasync 2015-09-04 00:40:08 +02:00
Markus Unterwaditzer
4b41f4050f Show differing etags in error msg 2015-09-03 15:45:08 +02:00
Markus Unterwaditzer
1182350af3 Add multifilesystem back 2015-08-21 16:19:55 +02:00
Markus Unterwaditzer
ef5e361927 Rename arguments for clarity 2015-08-20 17:22:54 +02:00
Markus Unterwaditzer
2d62ec9a26 Kill parse_pairs_args 2015-08-20 17:18:23 +02:00
Markus Unterwaditzer
8e2070e42d Add PairConfig and CollectionConfig 2015-08-20 16:42:43 +02:00
Markus Unterwaditzer
d59376e231 Remove unnecessary params, fix tests 2015-08-20 15:49:36 +02:00
Markus Unterwaditzer
0041934318 fix tests 2015-08-20 15:38:04 +02:00
Markus Unterwaditzer
ccb94a1c29 Create Config object 2015-08-20 15:19:25 +02:00
Markus Unterwaditzer
32abaae9b9 Move config tools to own file 2015-08-20 15:09:03 +02:00
Markus Unterwaditzer
565ef2e96e xfail owncloud, #255 2015-08-19 01:26:24 +02:00
Markus Unterwaditzer
930ea6a226 Fix tests for ownCloud
See https://github.com/owncloud/contacts/issues/1025
2015-08-18 21:25:44 +02:00
Markus Unterwaditzer
4f7589ca7f Fix logging 2015-08-18 21:25:19 +02:00
Markus Unterwaditzer
e687e9e7df Fix minimal requirements 2015-08-16 22:27:29 +02:00
Markus Unterwaditzer
30efccb959 Add changelog 2015-08-16 22:27:29 +02:00
Markus Unterwaditzer
c8014e5205 Merge pull request #241 from untitaker/click5
Factor out a few click-related things into extensions, new threading model
2015-08-16 20:00:50 +02:00
Markus Unterwaditzer
1aa6812bad Don't ask for same password twice 2015-08-16 19:45:39 +02:00
Markus Unterwaditzer
6e1846ea9d Remove custom ctx global 2015-08-16 19:40:00 +02:00
Markus Unterwaditzer
2fda4d6670 Add pipsi back to installation options 2015-08-12 23:01:31 +02:00
Markus Unterwaditzer
d59b310cd3 Version 0.6.0 2015-08-06 14:40:22 +02:00
Markus Unterwaditzer
2b5576c471 Fix error message
See #252
2015-08-06 11:48:43 +02:00
Markus Unterwaditzer
97d65ab222 Fix tests 2015-08-06 11:27:42 +02:00
Markus Unterwaditzer
4b25075b97 Merge branch 'mathstuf-full-ssl-verify'
Fix #252
2015-08-06 11:25:40 +02:00
Ben Boeckel
216e6c3b21 ssl: use verify and verify_fingerprint
Both have their uses. The latter is very strict in what it will accept,
but it does not catch expired certificates.
2015-08-06 11:25:06 +02:00
Markus Unterwaditzer
3836448cc3 Fix exitcodes in Makefile 2015-08-06 11:17:02 +02:00
Markus Unterwaditzer
2e83354c06 DAV: Remove check when fetching etags after PUT
Servers may automatically modify the item in unforeseeable ways.

Fix #251
2015-08-05 20:55:38 +02:00
Markus Unterwaditzer
fce0f8d74a Merge pull request #248 from tribut/wrongetagerror-message
Repair message for exception
2015-07-29 20:24:54 +02:00
Felix Eckhofer
d9802fc032 Repair message for exception 2015-07-28 18:42:28 +02:00
Markus Unterwaditzer
9229d08e55 Add another ticket link 2015-07-26 22:51:18 +02:00
Markus Unterwaditzer
5eab8ebb16 Fix Makefile 2015-07-26 15:32:59 +02:00
Markus Unterwaditzer
67c8c3f394 Improve UI of repair command 2015-07-26 14:40:11 +02:00
Markus Unterwaditzer
c51952d6fd Add some notes for packagers 2015-07-26 14:02:14 +02:00
Markus Unterwaditzer
20bacfe87e Don't install vdirsyncer from makefile 2015-07-26 13:59:37 +02:00
Markus Unterwaditzer
c812b5d50f Stylefix 2015-07-26 13:51:14 +02:00
Markus Unterwaditzer
7575fb21a7 Remove build.sh for good 2015-07-26 13:45:53 +02:00
Markus Unterwaditzer
10148f47f8 repair: Also fix hrefs, stricter safe-set
Fix #236
2015-07-26 12:04:14 +02:00
Markus Unterwaditzer
93480c059f Move hack for ownCloud bug into _normalize_href
Also refine the testsuite a bit to catch such problems.
2015-07-26 09:29:54 +02:00
Markus Unterwaditzer
edc0eb2f84 Refine race-check in dav._put 2015-07-25 04:03:28 +02:00
Markus Unterwaditzer
f0e842ac41 Split up caldav and carddav tests 2015-07-25 03:30:47 +02:00
Markus Unterwaditzer
4b0a896303 DAV: Remove warning about missing etag on PUT 2015-07-25 03:22:13 +02:00
Markus Unterwaditzer
7f705aeb3a Another note for packagers 2015-07-21 15:46:03 +02:00
Markus Unterwaditzer
552dc33037 stylefix 2015-07-20 17:56:57 +02:00
Markus Unterwaditzer
90aaa9d12a Add version.py to packages 2015-07-20 17:33:38 +02:00
Markus Unterwaditzer
60a7778cea Document password_command behavior in keyring.rst 2015-07-16 15:18:31 +02:00
Markus Unterwaditzer
0e11d2ea0e Use direct link to coveralls 2015-07-13 23:03:47 +02:00
Markus Unterwaditzer
4bb4b019ce Merge pull request #231 from untitaker/safe-hrefs
Create always safe hrefs
2015-07-13 13:19:03 +02:00
Markus Unterwaditzer
73e2ccf46a Create always safe hrefs
The set of safe characters was inspired by the set of safe characters in
URLs.

Fixes #229
2015-07-12 23:42:49 +02:00
Markus Unterwaditzer
04b3379172 Ignore DTSTAMP when hashing items 2015-07-12 18:44:58 +02:00
Markus Unterwaditzer
8e3f0ab05f Move discovery_cache_version 2015-07-09 10:04:07 +02:00
Markus Unterwaditzer
fcec7e1efd Don't leak worker threads 2015-07-09 10:04:07 +02:00
Markus Unterwaditzer
b58935c90d Fix tests again
Reverts f087ec599e
2015-07-09 00:10:02 +02:00
Markus Unterwaditzer
fc5175f7f3 Flake8 fixes 2015-07-08 20:42:26 +02:00
Markus Unterwaditzer
544a0790b5 Remove stub repl 2015-07-08 19:41:09 +02:00
Markus Unterwaditzer
8130789d39 Add click-repl as optdepend 2015-07-08 17:46:50 +02:00
Markus Unterwaditzer
283d6f98df doubleclick: Push ctx for subcommands 2015-07-08 17:16:35 +02:00
Markus Unterwaditzer
75d4f08c25 Bugfix: Actually cache passwords 2015-07-08 17:16:35 +02:00
Markus Unterwaditzer
2d5a230fa4 Style fixes 2015-07-07 16:51:31 +02:00
Markus Unterwaditzer
f8b781a6d4 repair: Traverse all subcomponents 2015-07-07 16:50:08 +02:00
Markus Unterwaditzer
e172fa43f3 Add changelog for #227 2015-07-07 16:37:32 +02:00
Markus Unterwaditzer
c84cfc0a29 Merge pull request #227 from untitaker/metadata
Metadata
2015-07-07 16:36:07 +02:00
Markus Unterwaditzer
d35cb1bc50 Tests for metasync 2015-07-07 16:32:47 +02:00
Markus Unterwaditzer
b44db992e7 Bidirectional sync 2015-07-07 16:32:47 +02:00
Markus Unterwaditzer
a007828f87 Simple metadata interface 2015-07-07 16:20:04 +02:00
Markus Unterwaditzer
f087ec599e This is not needed anymore 2015-07-07 16:19:27 +02:00
Markus Unterwaditzer
776bfa2f4f password_command failures are now fatal 2015-07-07 15:40:12 +02:00
Markus Unterwaditzer
39a11994f8 Remove useless sentence in CONTRIBUTING.rst 2015-07-07 13:37:08 +02:00
Markus Unterwaditzer
1bec5afc2f Rename example.cfg => config.example 2015-07-06 16:41:37 +02:00
Markus Unterwaditzer
31de43b4a9 Remove collection_human 2015-07-06 16:22:33 +02:00
Markus Unterwaditzer
acf3ac0dcd Add way to invalidate discovery cache 2015-07-06 16:21:37 +02:00
Markus Unterwaditzer
fe1d512b38 Fix tests 2015-07-06 12:40:15 +02:00
Markus Unterwaditzer
c9cc6e2aed Simplify error message 2015-07-06 07:36:57 +02:00
Markus Unterwaditzer
a446307d44 Remove silly handled_jobs 2015-07-05 23:06:44 +02:00
Markus Unterwaditzer
cad938d023 Fix flake8 2015-07-05 22:56:33 +02:00
Markus Unterwaditzer
aab878744a create vdirsyncer.repair 2015-07-05 22:18:36 +02:00
Markus Unterwaditzer
4d918b92c6 repair: When UID changes, don't re-use href 2015-07-05 13:32:04 +02:00
Markus Unterwaditzer
6fa3b1d3d7 DAV: Also allow : in href 2015-06-22 15:27:51 +02:00
Markus Unterwaditzer
7e6cf8cb28 There are always problems with computers 2015-06-19 00:12:00 +02:00
Markus Unterwaditzer
902c62c083 Add note regarding iCloud's 2fa
See #220
2015-06-18 23:43:00 +02:00
Markus Unterwaditzer
ad26e56b1d Remove watdo 2015-06-18 16:49:50 +02:00
Markus Unterwaditzer
b038a7816b Remove legacy error message 2015-06-18 03:27:55 +02:00
Markus Unterwaditzer
8fa041a0dd Add XXX flag 2015-06-18 03:11:20 +02:00
Markus Unterwaditzer
555e4b688a Python 2 fixes 2015-06-16 02:15:57 +02:00
Markus Unterwaditzer
4a17db5864 fix typo 2015-06-16 00:41:14 +02:00
Markus Unterwaditzer
1730cc34c9 Repair nonascii UIDs 2015-06-16 00:15:02 +02:00
Markus Unterwaditzer
3a8d5aed77 Version 0.5.2 2015-06-15 23:17:06 +02:00
Markus Unterwaditzer
e95f763b04 Merge pull request #218 from untitaker/specialchars-in-collection
Fix special chars once again
2015-06-15 19:18:08 +02:00
Markus Unterwaditzer
364912b496 Rewrite when.rst 2015-06-14 15:09:11 +02:00
Markus Unterwaditzer
d9a888abda Hopefully explain better what vdirs are 2015-06-14 14:28:33 +02:00
Markus Unterwaditzer
11929d8b34 Merge pull request #217 from untitaker/setuptools-scm
Switch to setuptools-scm
2015-06-13 19:17:09 +02:00
Markus Unterwaditzer
2866bbde5f Support unicode collections
- DAV: Avoid re-coding if possible
- Filesystem: Convert to native strings because that's what `os.path`
  utilities expect.
2015-06-13 18:15:21 +02:00
Markus Unterwaditzer
3cb6f3389d Changelog for #215 2015-06-13 14:07:23 +02:00
Markus Unterwaditzer
21667f2b06 Merge pull request #216 from untitaker/unicode_urls
Fix unicode URLs
2015-06-13 14:05:59 +02:00
Markus Unterwaditzer
237aacee7d Deal with unicode UIDs in sync 2015-06-12 02:51:34 +02:00
Markus Unterwaditzer
263a45e2a5 Fix unicode URLs 2015-06-12 02:51:34 +02:00
Markus Unterwaditzer
35c272dda2 Switch to setuptools-scm 2015-06-12 02:47:21 +02:00
Markus Unterwaditzer
a07c9bea44 decode_href => decode_url
Those functions can be applied to any URL
2015-06-11 15:30:50 +02:00
Markus Unterwaditzer
c4b4a4e8ad Mention MS tool for fixing broken Outlook events
See #214
2015-06-08 15:21:52 +02:00
Markus Unterwaditzer
d2f9c73079 Move link to first mention of Radicale 2015-06-07 11:25:08 +02:00
Markus Unterwaditzer
13ff39801b Elaborate on problems with davmail 2015-06-07 11:23:47 +02:00
Markus Unterwaditzer
e5c826ccfd Harden vdirsyncer against changing UIDs
In a strict sense not necessary since UIDs of an item must not be
changed.
2015-06-06 15:40:16 +02:00
Markus Unterwaditzer
548575bfaf Remove ppl from recommended software
The software drops unknown data fields and seems to be barely
maintained.
2015-06-06 06:40:07 +02:00
Markus Unterwaditzer
da87c0210c Use HTTPS links whenever possible 2015-06-05 15:40:44 +02:00
Markus Unterwaditzer
78efcf15de Stylefix 2015-06-05 14:55:19 +02:00
Markus Unterwaditzer
c830c2b5a4 Add when.rst 2015-06-05 14:46:54 +02:00
Markus Unterwaditzer
7ace6fb8f1 Permissions of status files are now checked
Also vdirsyncer now doesn't leak passwords from the config file into
the collection cache.

See #213.
2015-06-05 12:00:48 +02:00
Markus Unterwaditzer
2170a4fce2 Provide href on AlreadyExistingError
See #212
2015-06-05 00:13:59 +02:00
Markus Unterwaditzer
ce1c255152 Add info about collection-creation to docs 2015-06-04 12:58:05 +02:00
Markus Unterwaditzer
7d41378505 dav: Fully move collection management into Discover 2015-06-04 12:18:18 +02:00
Markus Unterwaditzer
ed6a65a6ab Add warning about missing etag 2015-06-04 10:55:29 +02:00
Markus Unterwaditzer
3fa7988ce4 Style fix 2015-06-03 14:18:14 +02:00
Markus Unterwaditzer
4f16f9c64e Deduplicate debug msg 2015-06-03 13:34:43 +02:00
Markus Unterwaditzer
7ef30202d6 Move imports for startup speed 2015-06-03 13:23:49 +02:00
Markus Unterwaditzer
b2fccdb484 Bugfix: Cache should be checked *before* command is called 2015-05-30 12:45:06 +02:00
Markus Unterwaditzer
224daba414 Add release cmd 2015-05-29 19:16:45 +02:00
Markus Unterwaditzer
46addd7e35 Version 0.5.1
https://bitbucket.org/pypa/pypi/issue/293/re-uploading-of-releases-is-completely
2015-05-29 19:14:32 +02:00
Markus Unterwaditzer
73fe27559d Don't upload ownCloud to PyPI 2015-05-29 16:28:09 +02:00
Markus Unterwaditzer
c83883d976 Fix Travis
At some point Travis apparently decided to set the default of the `sudo`
option to `false`. But that would mean I had to whitelist every package,
which is not acceptable.

http://docs.travis-ci.com/user/workers/container-based-infrastructure/
2015-05-27 15:48:14 +02:00
Markus Unterwaditzer
0c4e023c95 Fix typo 2015-05-26 22:21:54 +02:00
Markus Unterwaditzer
3cd216687e Copy cached_property from python-webuntis 2015-05-26 22:05:54 +02:00
Markus Unterwaditzer
c2a50d76a4 Remove usages of click.pass_context
And fix some bugs in doubleclick's obj proxy
2015-05-25 14:14:43 +02:00
Markus Unterwaditzer
3aa27f6d37 Keep opinions out of the docs
Especially the ones that are not mine :D
2015-05-25 11:02:26 +02:00
Markus Unterwaditzer
2aaeeb4e6b Merge branch 'tolerant-xml-parser' 2015-05-21 08:10:15 +02:00
Markus Unterwaditzer
209648a936 Make XML parsing more tolerant re invalid chars
Fix #207
2015-05-21 08:05:59 +02:00
Markus Unterwaditzer
6ed02b9a3e More refactoring in create_collection for DAV 2015-05-19 13:40:34 +02:00
Markus Unterwaditzer
4cfca383d9 Small refactor 2015-05-19 13:29:49 +02:00
Markus Unterwaditzer
5b4ca2975a Prevent users from hurting themselves 2015-05-18 20:00:32 +02:00
Markus Unterwaditzer
8fd16f9987 Merge pull request #205 from untitaker/fix-encodings
Fix encoding bug in upload
2015-05-15 17:03:32 +02:00
Markus Unterwaditzer
1b5bdc35da Fix encoding bug in upload
See #203
2015-05-15 08:36:21 +02:00
Markus Unterwaditzer
55be28c12b Obey useragent setting for DAV discovery 2015-05-15 00:34:53 +02:00
Markus Unterwaditzer
eec503b7d7 Remove hints about Google calendar, nothing works 2015-05-08 14:01:53 +02:00
Markus Unterwaditzer
157cd25151 Fix typo 2015-05-08 11:47:45 +02:00
Markus Unterwaditzer
4e8ae1e15f Merge pull request #200 from untitaker/handle-empty-items
Skip empty items
2015-05-07 22:32:59 +02:00
Markus Unterwaditzer
4adebe6026 Handle empty items properly
Fix #199
2015-05-06 21:39:57 +02:00
Markus Unterwaditzer
6ab6d1ddfd Check Python version at runtime 2015-05-02 15:45:15 +02:00
Markus Unterwaditzer
e4c3dafe4a Radicale's database storage is broken too 2015-05-01 15:57:54 +02:00
Markus Unterwaditzer
5f12be3687 Radicale-multifilesystem is broken 2015-05-01 14:46:20 +02:00
Markus Unterwaditzer
9f650e9adc Radicale-git is working now
See https://github.com/Kozea/Radicale/pull/259

Fix #176
2015-04-29 19:17:11 +02:00
Markus Unterwaditzer
46d61d23dc Fix a bug with string types in verify_fingerprint 2015-04-28 18:03:29 +02:00
Markus Unterwaditzer
dd0d399d82 Merge pull request #197 from untitaker/mustverify
Disallow verify=false
2015-04-28 17:57:51 +02:00
Markus Unterwaditzer
a90815f5df Improve errorhandling for enduser 2015-04-28 17:57:00 +02:00
Markus Unterwaditzer
8c7af4bfc9 Disallow verify=false 2015-04-28 16:56:05 +02:00
Markus Unterwaditzer
2b3e53a7d2 Expand on Radicale 2015-04-25 11:20:31 +02:00
Markus Unterwaditzer
6783abb65f Update DavMail section 2015-04-25 10:51:29 +02:00
Markus Unterwaditzer
598d3600cd stylefix 2015-04-23 16:49:41 +02:00
Markus Unterwaditzer
00c856eca0 Add warning about misbehavior 2015-04-23 15:53:59 +02:00
Markus Unterwaditzer
4d3f02b618 Add testcase for #194 2015-04-23 15:48:48 +02:00
Markus Unterwaditzer
e80f10aa99 Refactor join_collection
See #194
2015-04-23 15:47:18 +02:00
Markus Unterwaditzer
d37d85dc26 Rewrite split_collection
Related to #194
2015-04-23 15:21:27 +02:00
Markus Unterwaditzer
a32b8a9807 stylefix 2015-04-16 20:52:03 +02:00
Markus Unterwaditzer
951082c563 Improve wording 2015-04-16 20:11:08 +02:00
Markus Unterwaditzer
f0e4cf9ca7 Use only one worker if debug mode is activated 2015-04-16 20:09:49 +02:00
Markus Unterwaditzer
f23c79eac9 Fix compatibility with iCloud again 2015-04-14 10:29:30 +02:00
Markus Unterwaditzer
f32b4411ae Fix Py3 2015-04-13 23:19:55 +02:00
Markus Unterwaditzer
6d50112f97 Fix docs 2015-04-13 20:33:45 +02:00
Markus Unterwaditzer
aac97b1ae7 Fix broken import 2015-04-13 20:10:23 +02:00
Markus Unterwaditzer
ed12509c77 Lazily load storages 2015-04-13 18:28:11 +02:00
Markus Unterwaditzer
e2eb79d656 A lot of module restructuring
- Split utils up again
- Optimize performance when importing a specific storage. This is useful
  for khal which uses our FilesystemStorage (and doesn't want to import
  requests).
2015-04-13 17:33:44 +02:00
Markus Unterwaditzer
2320570217 Remove leftover FingerprintAdapter 2015-04-13 17:09:20 +02:00
Markus Unterwaditzer
172a2b9b98 Abort if VDIRSYNCER_CONFIG is invalid
Fix #193
2015-04-12 14:48:38 +02:00
Markus Unterwaditzer
90d283b3b8 Merge pull request #191 from untitaker/fingerprint-adapt
Use FingerprintAdapter from req-toolbelt
2015-04-12 14:42:57 +02:00
Markus Unterwaditzer
af2846570c More realistic example 2015-04-11 23:09:54 +02:00
Markus Unterwaditzer
fecfa90bb2 Clarify sensitivity of status data 2015-04-11 19:09:04 +02:00
Markus Unterwaditzer
1f8593ebbf Fix style 2015-04-11 16:42:03 +02:00
Markus Unterwaditzer
53414f5bee add testcase for #192 2015-04-11 15:19:14 +02:00
Markus Unterwaditzer
858fda7765 Merge pull request #192 from pierg75/handle-exception-wrong-config
handle a exception when the configuration is not correct
2015-04-11 15:18:49 +02:00
Pier
0647ed91c4 corrected the flake8 errors 2015-04-11 14:16:14 +01:00
Pier
287fe1dcbc corrections based on the feedback 2015-04-11 14:14:06 +01:00
Markus Unterwaditzer
575d270e06 Use FingerprintAdapter from req-toolbelt
Fix #187
2015-04-11 15:03:07 +02:00
Pier
cde248f887 handle a exception when the configuration is not correct 2015-04-11 12:25:33 +01:00
Markus Unterwaditzer
0a35e27d5d Fix missing line in changelog 2015-04-10 18:12:57 +02:00
Markus Unterwaditzer
1857ec50b2 Bump changelog 2015-04-10 18:12:10 +02:00
Markus Unterwaditzer
f3c8c93a2b Fix missing date in changelog -- again! 2015-04-10 18:11:50 +02:00
Markus Unterwaditzer
1cbb8f2274 Improve documentation on verify_fingerprint 2015-04-10 17:32:34 +02:00
Markus Unterwaditzer
d85da54300 Merge pull request #190 from untitaker/sync_rewrite
Another sync rewrite
2015-04-09 16:41:25 +02:00
Markus Unterwaditzer
e138af8d37 Allow storages to modify sync behavior 2015-04-09 15:19:51 +02:00
Markus Unterwaditzer
13408779cb Improve docs on filesystem's path param 2015-04-06 12:55:52 +02:00
Markus Unterwaditzer
aaafbd5d14 Add missing link 2015-03-31 01:23:01 +02:00
Markus Unterwaditzer
28d589e8eb Expand supported task managers 2015-03-31 00:42:10 +02:00
Markus Unterwaditzer
21f172e218 Merge pull request #189 from hobarrera/supported-todoman
Mention todoman as a supported client.
2015-03-31 00:25:43 +02:00
Hugo Osvaldo Barrera
d790a3bb5c Mention todoman as a supported client. 2015-03-30 17:19:42 -03:00
Markus Unterwaditzer
fb5f093bdf Test MKCOL in Radicale 2015-03-23 17:48:47 +01:00
Markus Unterwaditzer
8131166dce Version 0.4.4 2015-03-12 13:22:49 +01:00
Markus Unterwaditzer
a05b3f27a2 Add fedora package to docs 2015-03-11 16:53:00 +01:00
Markus Unterwaditzer
9446d388d0 Fix another bug during collection creation 2015-03-08 20:27:38 +01:00
Markus Unterwaditzer
cbc00630f2 style fix 2015-03-08 15:35:56 +01:00
Markus Unterwaditzer
25f209c3ca Create collections explicitly 2015-03-08 15:21:36 +01:00
Markus Unterwaditzer
264023c30d Fix bug in filesystem's create_collection 2015-03-08 15:00:51 +01:00
Markus Unterwaditzer
f17984559a Rephrasing in changelog 2015-03-08 14:43:59 +01:00
Markus Unterwaditzer
345581aa5b Add another test for full repair command 2015-03-07 22:51:02 +01:00
Markus Unterwaditzer
c73efe65af Add test for repair command 2015-03-07 22:43:48 +01:00
Markus Unterwaditzer
a5cb7b197b Move functionality to cli utils 2015-03-07 22:34:18 +01:00
Markus Unterwaditzer
c8c7305cbf Fix bug with UID parsing 2015-03-07 21:09:17 +01:00
Markus Unterwaditzer
07d90fa476 Fix severe bug with continuation lines 2015-03-07 21:05:50 +01:00
Markus Unterwaditzer
b2d0d9ce2e Improve repair-command's help 2015-03-07 21:00:06 +01:00
Markus Unterwaditzer
dd49b7e6fe Fix repair utility for new ical parser 2015-03-07 19:17:46 +01:00
Markus Unterwaditzer
8d5fed48bc Remove icalendar 2015-03-07 18:34:57 +01:00
Markus Unterwaditzer
42662a97c3 Add benchmarks to vobject parsing tests 2015-03-07 18:32:27 +01:00
Markus Unterwaditzer
fb5ed72c93 style fixes 2015-03-07 15:29:08 +01:00
Markus Unterwaditzer
9300069817 Remove click runners from test_config 2015-03-07 15:06:26 +01:00
Markus Unterwaditzer
1ca0859da1 Restructure CLI tests 2015-03-07 13:45:10 +01:00
Markus Unterwaditzer
6751880711 Assert that cache invalidation works fine 2015-03-07 13:33:13 +01:00
Markus Unterwaditzer
836623946d Avoid lookup in hashtable 2015-03-05 18:27:59 +01:00
Markus Unterwaditzer
a7e311dbf2 Remove linkcheck from travis 2015-03-04 21:21:02 +01:00
Markus Unterwaditzer
e5b75c571f Add _static path to git 2015-03-04 20:42:17 +01:00
Markus Unterwaditzer
f586f8ec37 Install vdirsyncer for stylecheck 2015-03-04 20:16:25 +01:00
Markus Unterwaditzer
b94b36a4eb Some link fixes 2015-03-04 19:39:26 +01:00
Markus Unterwaditzer
39a4bd3c73 Add strict checkers for docs 2015-03-04 19:38:06 +01:00
Markus Unterwaditzer
6e66b9d487 Fix broken link 2015-03-04 19:34:40 +01:00
Markus Unterwaditzer
6dac27d741 Improve UID parsing 2015-03-03 21:25:54 +01:00
Markus Unterwaditzer
a559021447 Add benchmarks 2015-03-03 21:25:54 +01:00
Markus Unterwaditzer
96eb309ab7 Style fixes 2015-02-26 12:34:33 +01:00
Markus Unterwaditzer
33d9d7d93e Convert to tuple before passing to requests
Requests accesses the cert tuple like this:

    if isinstance(cert, basestring):
        a = cert
    else:
        a = cert[0]
        b = cert[1]

On Python 3, map doesn't return a list, so (theoretically) this would
fail.
2015-02-26 12:22:10 +01:00
Markus Unterwaditzer
114c73537e Add changelog for #183 2015-02-26 12:17:57 +01:00
Markus Unterwaditzer
8f0fdcfcc1 Fix missing release date 2015-02-26 12:14:59 +01:00
Markus Unterwaditzer
af181cfe78 Add @mathstuf to authors 2015-02-26 12:14:00 +01:00
Markus Unterwaditzer
18103afcc2 Fix tests 2015-02-26 12:13:20 +01:00
Markus Unterwaditzer
1221350996 client cert doc: Add hints about fileexts 2015-02-26 12:11:19 +01:00
Markus Unterwaditzer
d77001d3bc Merge remote-tracking branch 'mathstuf/client-certs' 2015-02-26 12:10:31 +01:00
Ben Boeckel
9223899996 ssl: support client certificates
Password-protected keys are not supported.
2015-02-25 22:42:44 -05:00
Markus Unterwaditzer
2c6ccd1dfa Merge pull request #178 from untitaker/sync_rewrite
Sync rewrite
2015-02-25 16:05:49 +01:00
Markus Unterwaditzer
665b0cefaf Move ignored warnings into setup.cfg 2015-02-23 14:31:35 +01:00
Markus Unterwaditzer
0087f191dc Add convenience links to repo and docs 2015-02-23 00:40:20 +01:00
Markus Unterwaditzer
c8a7ad36de Compatibility with PyPy
On PyPy, dict.__reversed__ exists and raises a TypeError, on CPython, it
doesn't.

However, reversed({}) behaves the same on both sides.
2015-02-23 00:22:01 +01:00
Markus Unterwaditzer
f88e5f836d Don't care about that style check 2015-02-22 22:16:29 +01:00
Markus Unterwaditzer
08b6ce6b8c That test is broken on PyPy too 2015-02-22 22:01:10 +01:00
Markus Unterwaditzer
b2a68ec1a1 Test again under pypy 2015-02-22 20:17:50 +01:00
Markus Unterwaditzer
72123f00f0 Remove make install 2015-02-22 18:38:44 +01:00
Christian Geier
c28bcacdb3 expand paths before creating
this should close #179
2015-02-22 16:16:43 +01:00
Markus Unterwaditzer
2717c14e0c Hopefully fix this mutability bug completely 2015-02-22 15:13:23 +01:00
Markus Unterwaditzer
1e9fe12904 Another bugfix
See #179
2015-02-22 14:59:36 +01:00
Markus Unterwaditzer
6541b5b4af Don't do fsync on unix 2015-02-22 14:56:30 +01:00
Markus Unterwaditzer
a1a9cfef80 Revert "Skip collections during discovery, don't abort"
This reverts commit e35479b080.
2015-02-22 14:48:31 +01:00
Markus Unterwaditzer
eb9974f18d Fix broken import 2015-02-22 14:47:50 +01:00
Markus Unterwaditzer
0490930c5e Fix #180 2015-02-22 14:44:31 +01:00
Markus Unterwaditzer
e35479b080 Skip collections during discovery, don't abort 2015-02-22 14:42:58 +01:00
Markus Unterwaditzer
dec08780f3 Fix several bugs with collection creation in filesystem storage
See #179
2015-02-22 14:29:31 +01:00
Markus Unterwaditzer
6f77a9242c Werkzeug isn't directly required 2015-02-22 11:52:35 +01:00
Markus Unterwaditzer
3a0757d8ae Small improvement to readme 2015-02-21 18:58:51 +01:00
Markus Unterwaditzer
df55926c39 Sync rewrite 2015-02-21 14:14:43 +01:00
Markus Unterwaditzer
2a16f39c80 Version 0.4.3 2015-02-20 13:53:25 +01:00
Markus Unterwaditzer
732fc28081 Fix link 2015-02-20 13:52:55 +01:00
Markus Unterwaditzer
3f0415cc09 Add basic repair tool
Fix #172
2015-02-17 23:10:30 +01:00
Markus Unterwaditzer
1c1385762b Style fixes 2015-02-16 18:43:44 +01:00
Markus Unterwaditzer
34be98af51 Add iCloud instructions 2015-02-16 18:19:55 +01:00
Markus Unterwaditzer
f043bdfb12 Fix multiple issues with URL handling in discovery 2015-02-16 18:19:55 +01:00
Markus Unterwaditzer
6147da0676 Add some info on FastMail setup 2015-02-16 18:12:57 +01:00
Markus Unterwaditzer
1ded453284 Add section about Google support 2015-02-16 17:59:54 +01:00
Markus Unterwaditzer
60c96ae493 Remove is_subpath checks 2015-02-16 17:54:02 +01:00
Markus Unterwaditzer
943c970286 Don't rediscover if conflict_resolution changed 2015-02-15 21:29:58 +01:00
Markus Unterwaditzer
f7f271afe2 Add @michaeladler to AUTHORS 2015-02-15 12:36:16 +01:00
Markus Unterwaditzer
4e8ed832ae Expand on Radicale support 2015-02-14 18:44:36 +01:00
Markus Unterwaditzer
86bf936ff9 Shorten warning about DAV servers 2015-02-14 18:37:37 +01:00
Markus Unterwaditzer
c18dde68f4 Improve singlefile-storage warnings 2015-02-14 18:35:24 +01:00
Markus Unterwaditzer
c2fac4ac6f Improve docs for item_types 2015-02-14 18:31:27 +01:00
Markus Unterwaditzer
8275d23635 Remove some workarounds for Radicale 2015-02-14 18:25:15 +01:00
Markus Unterwaditzer
32a4bd9c16 Better documentation for mtime-helpers 2015-02-14 18:14:39 +01:00
Markus Unterwaditzer
54a07099b5 Add changelog entry regarding fixed MKCOL 2015-02-13 17:10:18 +01:00
Markus Unterwaditzer
084068545b More safety for singlefile storage 2015-02-12 13:20:19 +01:00
Markus Unterwaditzer
8e0d4d415e Remove one-time func after usage 2015-02-12 13:16:42 +01:00
Markus Unterwaditzer
2cd0a26a12 Check requests version at runtime 2015-02-12 12:24:24 +01:00
Markus Unterwaditzer
6dbe1f5eed Fix doc link 2015-02-10 13:17:35 +01:00
Markus Unterwaditzer
35305ad4c1 Fix MKCOL for Sabre DAV
Fix #175
2015-02-09 19:40:16 +01:00
Markus Unterwaditzer
ae9837ada2 Move footnote back up 2015-02-09 17:00:10 +01:00
Markus Unterwaditzer
a86088910d Workaround for #176 2015-02-09 16:14:22 +01:00
Markus Unterwaditzer
91d83d1b79 Style fixes 2015-02-09 15:45:01 +01:00
Markus Unterwaditzer
6207d9419c Don't actually tolerate this 2015-02-08 19:55:47 +01:00
Markus Unterwaditzer
ef18e78ca0 style fixes 2015-02-08 19:53:05 +01:00
Markus Unterwaditzer
e0167abf8c No need to show the full traceback here
Also I wouldn't consider it fatal if the hook fails.
2015-02-08 19:42:46 +01:00
Markus Unterwaditzer
58e1a027ef Introduce post_hook for filesystem storage
Fix #133
2015-02-08 19:40:07 +01:00
Markus Unterwaditzer
857395392e Move post_hook description to docs, changelog 2015-02-08 19:39:45 +01:00
Michael Adler
208453408f Introduce post_hook for filesystem storage 2015-02-08 19:37:10 +01:00
Markus Unterwaditzer
ba4407af13 Catch errors of Windows API 2015-02-08 14:57:53 +01:00
Markus Unterwaditzer
2831e17ae1 Flush more buffers when getting etag 2015-02-08 14:56:16 +01:00
Markus Unterwaditzer
6d91c95b30 Fix broken import 2015-02-08 14:50:13 +01:00
Markus Unterwaditzer
847f3b5142 Expect test to fail on case insensitive filesystems 2015-02-08 14:47:35 +01:00
Markus Unterwaditzer
6a9d7c191d Style fixes 2015-02-08 12:09:41 +01:00
Markus Unterwaditzer
792852c1fc Update PyPI description 2015-02-08 10:41:14 +01:00
Markus Unterwaditzer
d2a005cf8a We don't need the git version of Werkzeug anymore 2015-02-03 21:37:29 +01:00
Markus Unterwaditzer
32c84cc86e style fix 2015-02-02 19:51:45 +01:00
Markus Unterwaditzer
7d727ecef3 Fix various collection creation bugs 2015-02-02 19:22:17 +01:00
Markus Unterwaditzer
334ade7e6b style fix 2015-01-31 17:31:03 +01:00
Markus Unterwaditzer
08380c199e More performance improvements to singlefile 2015-01-31 10:35:53 +01:00
Markus Unterwaditzer
9014222af6 Add changelog entry for 0.4.3 2015-01-31 10:35:53 +01:00
Markus Unterwaditzer
4499ba73ec More instructions in readme, see #174 2015-01-30 16:12:50 +01:00
Markus Unterwaditzer
51564ff594 Version 0.4.2 2015-01-30 15:36:59 +01:00
Markus Unterwaditzer
fa54d3145a Add changelog for #173 2015-01-30 15:35:51 +01:00
Markus Unterwaditzer
4ddcb0fef4 Retry with random filename if UID is rejected.
see #173
2015-01-30 15:14:39 +01:00
Markus Unterwaditzer
0eb69a810f style fix 2015-01-29 13:06:54 +01:00
Markus Unterwaditzer
bdc66633b3 Implement Storage.at_once() 2015-01-29 12:49:00 +01:00
Markus Unterwaditzer
d07fe8376e Make stylechecker happy 2015-01-29 12:29:06 +01:00
Markus Unterwaditzer
b3b356e514 Introduce atomicwrites 2015-01-29 12:13:23 +01:00
Markus Unterwaditzer
27f5d54240 Add atomicwrites dependency 2015-01-29 12:12:40 +01:00
Markus Unterwaditzer
a2e71cc4ca Automatically create copyright year. 2015-01-28 21:38:02 +01:00
Markus Unterwaditzer
e96174a3c4 I not words 2015-01-24 21:26:19 +01:00
Markus Unterwaditzer
43e594fb43 Style fixes 2015-01-24 20:20:24 +01:00
Markus Unterwaditzer
500de6f081 Improve internal apis 2015-01-24 16:38:01 +01:00
Markus Unterwaditzer
76c7f034a7 Catch IdentConflict
Fix #170
2015-01-24 16:35:03 +01:00
Markus Unterwaditzer
cf622a75ea Don't print config variables twice
CarddavStorage doesn't override the __init__ method, which causes the
same spec from DavStorage to be loaded and printed twice.
2015-01-23 23:57:24 +01:00
Markus Unterwaditzer
5ce0d97f91 Remove copyright headers 2015-01-21 13:02:30 +01:00
Markus Unterwaditzer
73c5b688c1 Merge pull request #168 from untitaker/mates-add
Add mates as supported application
2015-01-20 16:55:08 +01:00
Markus Unterwaditzer
bbc8894ac2 Add mates as supported application 2015-01-20 16:37:13 +01:00
Markus Unterwaditzer
c5659018af Modify intro paragraph 2015-01-19 21:49:52 +01:00
Markus Unterwaditzer
3b04762653 Clean up XDG-basedir refs 2015-01-19 21:44:52 +01:00
Markus Unterwaditzer
868a099310 Add changelog for #166 and #167 2015-01-19 21:02:09 +01:00
Markus Unterwaditzer
c7bd51b56f Don't depend on global vars in daemon
See #167
2015-01-19 20:48:26 +01:00
Markus Unterwaditzer
a02fd034e4 Catch more errors in WorkerQueue
See #167
2015-01-18 21:52:22 +01:00
Markus Unterwaditzer
86bcf206fd depth=1 on calendar-query
Issue #166
2015-01-17 00:23:25 +01:00
Markus Unterwaditzer
1e0a768ccb Fix formatting and deprecated helptext 2015-01-14 00:15:11 +01:00
Markus Unterwaditzer
3c29bcea77 Elaborate on advantages of virtualenv 2015-01-13 23:39:10 +01:00
Markus Unterwaditzer
4c34a1e62d Add some more information on C dependencies 2015-01-13 23:34:10 +01:00
Markus Unterwaditzer
da8bba89de Fix bug 2015-01-12 20:45:15 +01:00
Markus Unterwaditzer
ce2cea130c Make status_path relative to config file 2015-01-12 20:16:10 +01:00
Markus Unterwaditzer
5fa05bce13 Fix for Python 3 2015-01-12 19:42:46 +01:00
Markus Unterwaditzer
55c2d1f619 Fix style issue 2015-01-12 19:41:48 +01:00
Markus Unterwaditzer
8ab9c429cc Rewrite safe_write 2015-01-12 00:32:49 +01:00
Markus Unterwaditzer
8a723febd3 Only calculate coverage from vdirsyncer itself. 2015-01-11 21:40:17 +01:00
Markus Unterwaditzer
c06acbb88a Merge pull request #164 from untitaker/buildenv-updates
Add makefile
2015-01-11 17:17:24 +01:00
Markus Unterwaditzer
a786fdf611 Add makefile
Hopefully I'll be able to move more and more stuff from build.sh to
standard build tools.
2015-01-11 16:57:55 +01:00
Markus Unterwaditzer
4d4c48ca12 Test minimal requirements 2015-01-11 14:34:05 +01:00
Markus Unterwaditzer
4384823cd1 Merge pull request #161 from untitaker/verify_docs
Document certificate verification properly
2015-01-10 23:44:10 +01:00
Markus Unterwaditzer
cda763fcc5 Set verify=False if verify_fingerprint is given 2015-01-10 23:31:55 +01:00
Markus Unterwaditzer
11bd19febf Make the SSL stuff into a new page 2015-01-10 23:01:34 +01:00
Markus Unterwaditzer
f76aeba9bc Some clarifications 2015-01-10 23:01:34 +01:00
Markus Unterwaditzer
3d62c19f42 Add comments on dependencies 2015-01-10 23:01:34 +01:00
Markus Unterwaditzer
7ddd3a5fdd Raise requests dep version 2015-01-10 23:01:34 +01:00
Markus Unterwaditzer
a1bf00837d Refer to SSL tutorial from config docs 2015-01-10 23:01:34 +01:00
Markus Unterwaditzer
ebedca1e85 add testcase 2015-01-10 23:01:34 +01:00
Markus Unterwaditzer
e3bc764515 Deduplicate HTTP storage args 2015-01-10 22:16:38 +01:00
Markus Unterwaditzer
d27e5b8329 Add documentation about certificate validation 2015-01-10 22:16:38 +01:00
Markus Unterwaditzer
12098bcc9d Add testcase for moved hrefs. 2015-01-10 22:06:56 +01:00
Markus Unterwaditzer
c2949a62b5 example.cfg cleanup 2015-01-10 12:05:39 +01:00
Markus Unterwaditzer
6ddb666234 3 > 2 2015-01-08 16:14:23 +01:00
Markus Unterwaditzer
07883c08df Don't doubly encode. 2015-01-08 14:00:43 +01:00
Markus Unterwaditzer
e6a5fbfb42 Follow redirects on PUT
Inspired by https://github.com/bitfireAT/davdroid/issues/414
2015-01-07 17:47:27 +01:00
Markus Unterwaditzer
c2750e025e Add changelog entry for 0.4.2 2015-01-07 17:46:11 +01:00
Markus Unterwaditzer
dfc30b794d Link more directly to supported servers 2015-01-06 14:24:04 +01:00
Markus Unterwaditzer
c5fba836d3 Version 0.4.1 2015-01-05 12:52:06 +01:00
Markus Unterwaditzer
978abc6872 add changelog entry for Baikal 2015-01-05 12:51:55 +01:00
Markus Unterwaditzer
47663ae4ee Add section on Baikal 2015-01-05 12:51:18 +01:00
Markus Unterwaditzer
d4e3b99311 Add new workaround for #140 (debian bs) 2015-01-05 12:44:47 +01:00
Markus Unterwaditzer
07b5b1eae9 Link fixes 2015-01-04 16:24:06 +01:00
Markus Unterwaditzer
f0fe282865 props might be an empty list, not None. 2015-01-04 16:23:45 +01:00
Markus Unterwaditzer
a55d1f2d03 Re-enable baikal tests 2015-01-04 13:43:53 +01:00
Markus Unterwaditzer
0ada12ea00 Remove baikal from test config again 2015-01-04 00:34:05 +01:00
Markus Unterwaditzer
742109f542 Skip collections first
This avoids FUD errors later when trying to access e.g. etags for it.
2015-01-04 00:26:33 +01:00
Markus Unterwaditzer
863d574261 A lot of bugfixes
- There may be multiple prop-tags, and vdirsyncer only picked one of
  them, seemingly at random.

- getcontenttype doesn't work for everything

These bugs were found with Baikal 0.2.7
2015-01-04 00:15:05 +01:00
Markus Unterwaditzer
ccc3dee28b Handle UID conflicts during sync 2015-01-03 16:30:23 +01:00
Markus Unterwaditzer
aad6d23ed6 Fix leftover for #158 2015-01-03 02:02:41 +01:00
Markus Unterwaditzer
98c01cdc37 Merge pull request #159 from untitaker/dav_cleanup
Dav cleanup
2015-01-03 02:01:29 +01:00
Markus Unterwaditzer
9a64af85d5 Clean up DAV collection discovery 2015-01-03 01:35:20 +01:00
Markus Unterwaditzer
8178e5ff67 Move methods around for legibility 2015-01-02 22:36:37 +01:00
Markus Unterwaditzer
eef269507f Only catch HTTPErrors
Connection timeouts should not be interpreted as missing server support.
2015-01-02 22:30:43 +01:00
Markus Unterwaditzer
c1653937d1 Simplify XML query 2015-01-02 21:09:49 +01:00
Markus Unterwaditzer
51a8312f1e Trim ridiculously long path 2015-01-01 23:53:04 +01:00
Markus Unterwaditzer
6f95870a48 Remove old config value style 2015-01-01 23:28:54 +01:00
Markus Unterwaditzer
95e81f5383 Remove leftovers 2015-01-01 22:06:12 +01:00
Markus Unterwaditzer
998a3884fd Merge branch 'unify_creation'
fix #157
2015-01-01 22:02:05 +01:00
Markus Unterwaditzer
fab29b4ecb Test collection creation explicitly 2015-01-01 22:01:24 +01:00
Markus Unterwaditzer
8e694a2a2f Don't test collection creation indirectly 2015-01-01 22:01:24 +01:00
Markus Unterwaditzer
67ff41e820 docs and changelog 2015-01-01 22:01:24 +01:00
Markus Unterwaditzer
fcf901e620 Show original error message 2015-01-01 22:01:23 +01:00
Markus Unterwaditzer
e76fd29aec Unify collection creation 2015-01-01 22:01:23 +01:00
Markus Unterwaditzer
0618a45a28 Introduce CollectionNotFound 2015-01-01 22:01:23 +01:00
Markus Unterwaditzer
cc0b8ad028 join_collection => create_collection 2015-01-01 22:01:23 +01:00
Markus Unterwaditzer
584e1d9d12 Add new testcase
see #144
2015-01-01 19:13:13 +01:00
Markus Unterwaditzer
401d6fbf4f Improve "supported servers" docs 2015-01-01 19:06:03 +01:00
Markus Unterwaditzer
b03e9fb21f Fix #158 2015-01-01 16:53:16 +01:00
Markus Unterwaditzer
7bb7191526 Catch less errors 2015-01-01 16:22:00 +01:00
Markus Unterwaditzer
b548c27384 Remove unnecessary imports 2015-01-01 13:17:04 +01:00
Markus Unterwaditzer
e21a197006 The original testcase already takes care of this. 2015-01-01 13:05:39 +01:00
Markus Unterwaditzer
6c0223f048 Add 0.4.1 to changelog 2014-12-31 14:21:02 +01:00
Markus Unterwaditzer
bf81c769f8 Remove superfluous testcase. 2014-12-31 01:42:52 +01:00
Markus Unterwaditzer
38c1c77508 Version 0.4.0 2014-12-31 01:19:19 +01:00
Markus Unterwaditzer
0d3dc10b35 Remove old config format
Fix #148
2014-12-31 01:13:26 +01:00
Markus Unterwaditzer
b0d969df0d Fix Python 3 syntax 2014-12-30 18:28:51 +01:00
Markus Unterwaditzer
e5d27d771d Style fixes 2014-12-30 18:13:55 +01:00
Markus Unterwaditzer
e933f6db44 Ensure updated items have the same UID (if any)
FastMail insists on this.
2014-12-30 18:07:27 +01:00
Markus Unterwaditzer
9ede54ed9b Add join_collection to DavStorage 2014-12-30 17:57:18 +01:00
Markus Unterwaditzer
f6f103d1c1 WIP 2014-12-30 17:04:02 +01:00
Markus Unterwaditzer
0f5bf97174 Fix typo 2014-12-30 16:53:54 +01:00
Markus Unterwaditzer
b3e649d1b3 Don't catch that many exceptions 2014-12-30 16:53:03 +01:00
Markus Unterwaditzer
e8254f489e Fix logging 2014-12-30 13:56:12 +01:00
Markus Unterwaditzer
ce30ed7b8a Rewrite collections test 2014-12-30 13:23:45 +01:00
Markus Unterwaditzer
40b64139fd Add item_types test 2014-12-28 00:40:35 +01:00
Markus Unterwaditzer
8933da7db4 Add example configuration to storage docs 2014-12-27 16:44:18 +01:00
Markus Unterwaditzer
8c93247aa0 Fix footnote 2014-12-27 16:44:18 +01:00
Markus Unterwaditzer
9b442ebcf3 Enforce read-only attribute 2014-12-27 11:28:31 +01:00
Markus Unterwaditzer
1d8c606005 dav: Encode generated href 2014-12-27 00:33:22 +01:00
Markus Unterwaditzer
e450baf0f8 finally silence flake8 2014-12-26 10:04:51 +01:00
Markus Unterwaditzer
37cd8aa88d Ignore error (not warning) 2014-12-26 01:23:38 +01:00
Markus Unterwaditzer
cdb25d61ec Move config parsing into cli module 2014-12-26 00:58:41 +01:00
Markus Unterwaditzer
6ef330aac5 Stricter config validation 2014-12-26 00:50:15 +01:00
Markus Unterwaditzer
4757fac383 Don't raise errors if directories don't exist 2014-12-26 00:50:03 +01:00
Markus Unterwaditzer
11c9541b53 Add more output to discover command. 2014-12-25 23:59:02 +01:00
Markus Unterwaditzer
f2d34f4784 Create cli.tasks 2014-12-25 23:59:02 +01:00
Markus Unterwaditzer
e297e6848a Simplify example.cfg 2014-12-25 18:26:17 +01:00
Markus Unterwaditzer
2a3b56c179 Don't actually follow redirects 2014-12-23 22:41:57 +01:00
Markus Unterwaditzer
b04638246a Simplify request functions 2014-12-23 22:39:56 +01:00
Markus Unterwaditzer
3258a59e99 Simplify code 2014-12-23 22:34:04 +01:00
Markus Unterwaditzer
2a80dfae30 Improve DAV discovery
- Fix #156, .well-known URIs are now supported.

- More resilience against error responses, which are not surprising
  given that we send partially invalid requests in order to brute-force
  the home-set URL.
2014-12-23 22:21:30 +01:00
Markus Unterwaditzer
839f53e872 More doc fixes 2014-12-22 19:41:30 +01:00
Markus Unterwaditzer
ba99c599c3 More refactoring 2014-12-22 01:27:55 +01:00
Markus Unterwaditzer
a949b07233 More refactoring 2014-12-21 23:52:50 +01:00
Markus Unterwaditzer
c2ec4cd3a3 Testsuite refactoring 2014-12-21 13:58:47 +01:00
Markus Unterwaditzer
548b397dbb Fix a refactoring bug 2014-12-20 13:50:01 +01:00
Markus Unterwaditzer
7b2bc1bc38 Add docstring 2014-12-20 03:03:02 +01:00
Markus Unterwaditzer
e0316880b4 Use helper function 2014-12-20 02:56:35 +01:00
Markus Unterwaditzer
a19838327d function call cleanup 2014-12-20 02:54:31 +01:00
Markus Unterwaditzer
14699d3195 Fix test 2014-12-20 02:30:54 +01:00
Markus Unterwaditzer
e717be9681 Redraw API borders 2014-12-20 02:27:51 +01:00
Markus Unterwaditzer
cfe252d458 Make .cli a subpackage 2014-12-20 01:59:59 +01:00
Markus Unterwaditzer
ecb40579df Update some docs to new config format 2014-12-20 00:13:26 +01:00
Markus Unterwaditzer
3101572440 Add note regarding radicale bug
https://github.com/Kozea/Radicale/pull/236
2014-12-17 16:54:10 +01:00
Markus Unterwaditzer
0ddd52d14f Add changelog for #152 2014-12-17 15:16:45 +01:00
Markus Unterwaditzer
90c9f227f3 Rename passwordeval to password_command
Fix #139
2014-12-17 14:58:26 +01:00
Markus Unterwaditzer
4aab600e7c Prettify error message 2014-12-17 14:29:09 +01:00
Markus Unterwaditzer
625cb4adde Changelogs should now be written immediately
...and together with the accompanying patch.
2014-12-17 14:25:50 +01:00
Markus Unterwaditzer
c0c33efade Point to stable docs 2014-12-16 20:27:11 +01:00
Markus Unterwaditzer
d6fd9f6b3b Remove useless adjective 2014-12-16 18:16:48 +01:00
Markus Unterwaditzer
8266145443 Remove storage defaults from pair section
This feature didn't seem to be documented anyway.
2014-12-16 18:15:51 +01:00
Markus Unterwaditzer
d19ee9fa27 Merge pull request #151 from untitaker/discovery
Discovery
2014-12-16 17:50:59 +01:00
Markus Unterwaditzer
e219139e08 Add docs on collection discovery 2014-12-16 17:49:42 +01:00
Markus Unterwaditzer
2e2349c46d Add discover command 2014-12-16 17:20:02 +01:00
Markus Unterwaditzer
06a701bc10 Handle collections correctly
Fix #132

Passing the collections parameter used to mean that the storage should
append its value to the URL or path. This was a leaky abstraction for
the reasons explained in #132.

The new behavior removes this meaning from this parameter. Vdirsyncer
now maintains a cache of discovered collections.
2014-12-15 21:57:56 +01:00
Markus Unterwaditzer
1e8e931464 Clarify internal docstring 2014-12-15 21:18:37 +01:00
Markus Unterwaditzer
6b199474a6 Factor out deprecated config parsing 2014-12-15 21:12:54 +01:00
Markus Unterwaditzer
b3964ee8bb Add @hobarrera to AUTHORS 2014-12-15 21:07:12 +01:00
Markus Unterwaditzer
3fbdeb51c0 Add docs about new restriction 2014-12-15 20:55:36 +01:00
Markus Unterwaditzer
d9e4a5b767 Validate section names more strictly
This avoids any problems with status files
2014-12-15 20:52:32 +01:00
Markus Unterwaditzer
ddc47c2272 --force-delete is now a flag
Conflicts:
	tests/test_cli.py
	vdirsyncer/cli.py
2014-12-15 20:46:34 +01:00
Markus Unterwaditzer
a1f2d14c05 Refactor parse_config to use fileobject 2014-12-15 20:37:23 +01:00
Markus Unterwaditzer
cb44046a8a Make global variables immutable 2014-12-15 20:26:51 +01:00
Markus Unterwaditzer
6f959b3bd3 Factor out worker queue code from sync function 2014-12-15 20:16:36 +01:00
Markus Unterwaditzer
ddd8ab675e Merge pull request #152 from hobarrera/xdg-basedir
Support the XDG-Basedir specification
2014-12-15 19:58:33 +01:00
Hugo Osvaldo Barrera
41a92528ca Update doc as per latest feedback. 2014-12-15 15:55:54 -03:00
Markus Unterwaditzer
eb5587f4ca Fix racecondition in status creation 2014-12-15 19:16:33 +01:00
Hugo Osvaldo Barrera
ff72e34826 Document XDG-Basedir compatibility.
Document that it's possible to place the configuration file in and XDG-Basedir
compliant location.
2014-12-14 17:57:13 -03:00
Hugo Osvaldo Barrera
4c7042da56 Use XDG-Basedir as a fallback for configuration file location. 2014-12-14 17:45:48 -03:00
Markus Unterwaditzer
e40ba55bd3 Build fixes 2014-12-11 21:51:03 +01:00
Markus Unterwaditzer
632a60585c Enable radicale-multifilesystem in Travis
IIRC I disabled it because I thought it would be a waste of power. There
haven't been any recent developments in that regard, but nowadays I
don't think so anymore.
2014-12-11 20:43:35 +01:00
Markus Unterwaditzer
3f41930f7b Version 0.3.4 2014-12-11 20:13:04 +01:00
Markus Unterwaditzer
d91512d07e Even more fixes to config parsing 2014-12-11 20:12:59 +01:00
Markus Unterwaditzer
43ff90da9a Version 0.3.3 2014-12-11 19:04:28 +01:00
Markus Unterwaditzer
291edd7be0 Merge branch 'encodings'
Conflicts:
	vdirsyncer/storage/dav.py
2014-12-08 20:13:41 +01:00
Markus Unterwaditzer
61bf23588d Refactor! 2014-12-08 16:32:23 +01:00
Markus Unterwaditzer
ee3f0ad300 Skip broken props in get_multi 2014-12-08 15:27:00 +01:00
Markus Unterwaditzer
25aff68b50 Remove DAV header check
iCloud doesn't return anything useful while working fine otherwise.
2014-12-08 15:12:24 +01:00
Markus Unterwaditzer
3b6a2f3664 Clean up set comparison 2014-12-08 11:27:04 +01:00
Markus Unterwaditzer
ca5a9cd8f9 Stricten collection discovery test 2014-12-07 16:49:52 +01:00
Markus Unterwaditzer
741045c1be Rewrite DAV storages' encoding behavior
This is more explicit than the old behavior. See
https://github.com/Kozea/Radicale/issues/128 for the discussion that led
to this.
2014-12-07 15:11:42 +01:00
Markus Unterwaditzer
7f2ccd6b3a Style fixes 2014-12-07 15:01:01 +01:00
Markus Unterwaditzer
6fd5f0aaa9 Don't consume iterator twice 2014-12-07 14:52:41 +01:00
Markus Unterwaditzer
07de8a0cc4 Add another test re s.has 2014-12-06 16:40:39 +01:00
Markus Unterwaditzer
a0760ca171 Invalid hrefs technically don't exist 2014-12-06 16:30:40 +01:00
Markus Unterwaditzer
772f745832 get_multi now ignores duplicate input 2014-12-06 14:08:10 +01:00
Markus Unterwaditzer
d14fcbc59a Fix bug with DAV href generation 2014-12-06 12:12:56 +01:00
Markus Unterwaditzer
5ebc9eaecb Remove leftover assertion 2014-12-06 12:12:56 +01:00
Markus Unterwaditzer
24b492c610 Fix item_types parser 2014-12-06 10:21:12 +01:00
Markus Unterwaditzer
448dc9b6b7 Fix logging output 2014-12-06 10:09:56 +01:00
Markus Unterwaditzer
2331356333 Update CONTRIBUTING 2014-12-05 23:25:18 +01:00
Markus Unterwaditzer
2be78545fd Fix a bug in DAV discovery
Server might return relative URLs (iCloud does)
2014-12-05 15:39:20 +01:00
Markus Unterwaditzer
48d0631c3d Small restructuring 2014-12-03 19:33:07 +01:00
Markus Unterwaditzer
a1d453d46c Rewrite CONTRIBUTING 2014-12-03 19:12:09 +01:00
Markus Unterwaditzer
1efb00b5f7 Version 0.3.2 2014-12-03 17:32:24 +01:00
Markus Unterwaditzer
e5ee8fcd66 Merge pull request #142 from untitaker/json_config
New config format
2014-12-03 17:30:07 +01:00
Markus Unterwaditzer
08c07c4be4 New config format
See #141

Basically this tries to parse config values with JSON, if that fails,
the value is interpreted as string.

I'd greatly appreciate feedback on this and #141
2014-12-02 21:03:06 +01:00
Markus Unterwaditzer
566a988f32 Remove indirection for get_storage_args fixture 2014-12-01 00:11:23 +01:00
Markus Unterwaditzer
c234bce656 "A from B" => "B/A" 2014-12-01 00:11:05 +01:00
Markus Unterwaditzer
07fbd9cb89 Remove unused variable 2014-11-30 20:24:44 +01:00
Markus Unterwaditzer
29f9a10766 Skip non-directories during filesystem discovery 2014-11-30 16:02:01 +01:00
Markus Unterwaditzer
11919ef30d Disable Radicale multifilesystem 2014-11-30 13:50:44 +01:00
Markus Unterwaditzer
a7878c9342 Add radicale multifilesystem to test matrix 2014-11-30 13:41:09 +01:00
Markus Unterwaditzer
a29c60c58d AFAIK requests comes with its own CA bundle now 2014-11-28 19:22:33 +01:00
Markus Unterwaditzer
af3b081e27 Update debian problems in response to #140 2014-11-28 19:16:57 +01:00
Markus Unterwaditzer
977ba4c285 Remove any mention of pipsi
As usual for Armin, excellent software with excellent design, but
basically no maintenance.
2014-11-28 18:35:35 +01:00
Markus Unterwaditzer
bd235df3c8 Actually fix #138 2014-11-27 14:01:44 +01:00
Markus Unterwaditzer
069f5dfa89 Deal with Radicale 0.7
Fix #138
2014-11-26 14:19:46 +01:00
Markus Unterwaditzer
37c2467f59 Stricten testsuite 2014-11-25 15:17:51 +01:00
Markus Unterwaditzer
29cf9e0b50 Version 0.3.1 2014-11-24 20:57:21 +01:00
Markus Unterwaditzer
0ac80f365d Merge entries for supported graphical calendars 2014-11-23 09:53:15 +01:00
Markus Unterwaditzer
5b70688402 Remove FUD 2014-11-20 18:06:43 +01:00
Markus Unterwaditzer
7d6c8b29ce Add more stuff to the tutorial
Fix #136
2014-11-20 18:04:25 +01:00
Markus Unterwaditzer
4fd4e21cc6 Rewrite introductory paragraph 2014-11-20 17:51:30 +01:00
Markus Unterwaditzer
0f5fdd6d39 add comment 2014-11-20 13:52:24 +01:00
Markus Unterwaditzer
09f3ad10fb fix whitespace 2014-11-18 18:04:29 +01:00
Markus Unterwaditzer
de829e4cfd Also allow default theme for documentation.
Fix #134
2014-11-18 17:17:42 +01:00
Markus Unterwaditzer
ca7a5318ca fix heading in vdir spec 2014-11-16 14:21:01 +01:00
Markus Unterwaditzer
f113b1d1e3 What rationale? 2014-11-16 14:20:18 +01:00
Markus Unterwaditzer
0c7f73bfe6 Add note about new features to CONTRIBUTING 2014-11-15 15:19:08 +01:00
Markus Unterwaditzer
ca30542801 Test against more item types 2014-11-04 21:16:37 +01:00
Markus Unterwaditzer
0e68966963 Disable baikal tests for now 2014-11-03 15:35:35 +01:00
Markus Unterwaditzer
a0c749a3b1 Test baikal
See #130
2014-11-03 14:24:19 +01:00
Markus Unterwaditzer
df305fc14e Fix style 2014-11-03 14:23:54 +01:00
Markus Unterwaditzer
6bf0df4d89 Use safe_write for statuses 2014-11-02 23:34:05 +01:00
Markus Unterwaditzer
bf88c44ca1 Merge pull request #129 from untitaker/donation_buttons
Add donation buttons
2014-11-02 22:01:03 +01:00
Markus Unterwaditzer
b6defc4a45 Add donation buttons 2014-11-02 21:59:14 +01:00
Markus Unterwaditzer
3fccfe19e7 Enforce alphabetic import order 2014-10-29 23:03:58 +01:00
Markus Unterwaditzer
ad128d37c5 Some doc improvements 2014-10-29 21:31:18 +01:00
Markus Unterwaditzer
f4134f0918 fix typo 2014-10-27 23:02:09 +01:00
Markus Unterwaditzer
6a4506a9da "keep track of THE files" 2014-10-27 20:15:16 +01:00
Markus Unterwaditzer
be8c3c4f02 Fix reference 2014-10-27 20:14:09 +01:00
Markus Unterwaditzer
867148dd45 Update installation docs 2014-10-27 20:12:41 +01:00
Markus Unterwaditzer
0fd026a81e Update CONTRIBUTING 2014-10-26 20:54:26 +01:00
Markus Unterwaditzer
9be288b70d Add support page 2014-10-26 20:52:52 +01:00
Markus Unterwaditzer
9d3a9611b2 Fix typo 2014-10-21 19:35:49 +02:00
Markus Unterwaditzer
4857292b5c New testcases for vobject joining 2014-10-21 18:26:02 +02:00
Markus Unterwaditzer
6bd5bf7422 Simplify sync code
Before deletion, vdirsyncer will now check if the item changed on the
other side, and induce a re-upload if the item did change.

Because of this behavior it is now possible to remove the special-casing
if no status is available.

Fix #128
2014-10-20 17:42:45 +02:00
Markus Unterwaditzer
f22548000b Fix another typo and add test assertion 2014-10-19 18:36:09 +02:00
Markus Unterwaditzer
c5c5208662 Bugfix: http storage: Actually respect useragent 2014-10-19 18:26:55 +02:00
Markus Unterwaditzer
5a26721905 Fix typo 2014-10-19 15:49:58 +02:00
Markus Unterwaditzer
75bd145507 Improvements to singlefile storage 2014-10-19 15:29:42 +02:00
Markus Unterwaditzer
2fd74c8cbe add disclaimer 2014-10-19 14:53:58 +02:00
Markus Unterwaditzer
05dbe56acf Add dayplanner to list of supported applications 2014-10-19 14:50:16 +02:00
Markus Unterwaditzer
c759069c0d Add github issue link role 2014-10-19 13:48:09 +02:00
Markus Unterwaditzer
79e627d429 Add description in latex docs 2014-10-19 13:22:44 +02:00
Markus Unterwaditzer
e9200ff6a2 Why did i capitalize this? 2014-10-19 13:00:56 +02:00
Markus Unterwaditzer
9290b9132f Specify minimum versions for dependencies 2014-10-19 12:28:33 +02:00
Markus Unterwaditzer
e270e78bb3 These dots annoy me 2014-10-18 22:34:40 +02:00
Markus Unterwaditzer
c33e67fb81 Remove processes param completely from docs 2014-10-18 22:27:50 +02:00
Markus Unterwaditzer
214756f28c Change context manager to normal function 2014-10-18 17:44:05 +02:00
Markus Unterwaditzer
6ac71e0e7c Merge pull request #126 from untitaker/issue124
Stop using multiprocessing.dummy.Pool
2014-10-18 17:22:04 +02:00
Markus Unterwaditzer
734fdd61f6 Improve conflict_resolution docs 2014-10-18 16:37:45 +02:00
Markus Unterwaditzer
9688eb3a2c Also clarify for contacts 2014-10-18 16:33:39 +02:00
Markus Unterwaditzer
aba0a40fbc Move exception handling into context manager 2014-10-16 21:40:49 +02:00
Markus Unterwaditzer
93d29972ec Add testcase 2014-10-16 21:40:49 +02:00
Markus Unterwaditzer
29d80b7be0 Stop using multiprocessing.dummy.Pool
- Custom job queue with workers based on threads.
- Collection discovery is now done in a separate thread. Due to the
  gained flexibility, we could do the sync actions in separate threads
  too?
- The processes parameter has been removed, the related new option is
  only available on the CLI.
2014-10-16 21:40:49 +02:00
Markus Unterwaditzer
ac942bff67 Fix broken link 2014-10-16 21:10:30 +02:00
Markus Unterwaditzer
d404c8c62a Merge pull request #123 from untitaker/vdir_multiple_events
vdir: Clarify how many items are allowed in one file
2014-10-14 18:16:13 +02:00
Markus Unterwaditzer
9b00fd89d8 vdir: Clarify how many items are allowed in one file 2014-10-14 18:15:57 +02:00
Markus Unterwaditzer
6280708aee Prefetch less 2014-10-10 18:58:57 +02:00
Markus Unterwaditzer
2d62c8716b Continue syncing pairs if one pair crashes
Fix #121

Vdirsyncer used to exit as a whole when one pair failed to synchronize
due to connection errors. The new behavior actually tries to synchronize
other pairs before exiting with a nonzero status code. The old behavior
can be restored with the --fail-fast flag.
2014-10-08 22:03:04 +02:00
Markus Unterwaditzer
8bb25e3fb2 Rename "API" to "Config"
This is not actually a programming interface.
2014-10-08 20:33:30 +02:00
Thomas Weißschuh
0441fe7354 fix link definition in docs 2014-10-05 19:28:56 +00:00
Thomas Weißschuh
f3a67ed1f8 mention contactquery.c in docs
see #25
2014-10-05 19:28:30 +00:00
Markus Unterwaditzer
fefaf658f0 Shorten links 2014-10-05 20:04:06 +02:00
Markus Unterwaditzer
9b6dba8511 Add Orage and khard to client apps
Fix #122
2014-10-03 15:05:07 +02:00
Markus Unterwaditzer
281b537531 Fix module header 2014-09-28 14:13:21 +02:00
Markus Unterwaditzer
19b324f5f2 Better build errors 2014-09-23 21:30:17 +02:00
Markus Unterwaditzer
cdd0d21f33 I did it again... 2014-09-23 21:29:55 +02:00
Markus Unterwaditzer
036f786ed3 Add tests to distribution
See #119
2014-09-23 17:58:48 +02:00
Markus Unterwaditzer
27682f130d Add supported software 2014-09-23 17:47:37 +02:00
Markus Unterwaditzer
0e693c5bfe Add tags feed 2014-09-22 18:20:48 +02:00
Markus Unterwaditzer
d5d55d084c Version 0.3.0 2014-09-20 14:37:50 +02:00
Markus Unterwaditzer
32dbba8c44 Add documentation for `passwordeval` parameter. 2014-09-20 14:20:54 +02:00
Markus Unterwaditzer
fcf0f003aa Merge branch 'outlook_fixes' 2014-09-20 14:06:42 +02:00
Markus Unterwaditzer
1db680eb4d Internal API and doc improvements 2014-09-19 23:53:08 +02:00
Markus Unterwaditzer
5539ec26e9 Recommend system packages over pip
Including pkgsrc package by @0-wiz-0 and AUR package by @hobarrera.
2014-09-13 20:36:32 +02:00
Markus Unterwaditzer
37551b376f Rely on Python 3 to decode stdout. 2014-09-13 14:56:29 +02:00
Markus Unterwaditzer
14f7da4e04 Change command error to warning
Also fix some smaller stilistic things
2014-09-13 14:38:51 +02:00
Markus Unterwaditzer
1699324304 Add docs for passwordeval function 2014-09-13 14:34:16 +02:00
Markus Unterwaditzer
3ad598c7b4 Merge pull request #117 from vimbaer/passwordeval
New general config option: passwordeval
2014-09-13 14:29:54 +02:00
Markus Unterwaditzer
1c1aadedc0 Change exception to warning 2014-09-12 16:57:33 +02:00
vimbaer
23a4a96cb9 Fixed style. 2014-09-12 00:02:11 +02:00
vimbaer
64e9ef7dc3 Renamed evalcmd -> command, use py.test's tmpdir, allow arguments in passwordeval option. 2014-09-11 23:33:44 +02:00
vimbaer
4e895b8635 Added passwordeval as an option for the general config section. If no password is provided the command provided as passwordeval will be called with username and hostname as arguments. 2014-09-10 22:03:05 +02:00
Markus Unterwaditzer
9dbb359569 Fix failing testcase 2014-09-10 16:39:25 +02:00
Markus Unterwaditzer
4f05962cb0 Merge remote-tracking branch 'origin/keyring_bugfix'
Fix #116
2014-09-09 17:49:06 +02:00
Markus Unterwaditzer
3bb6662e8e Add testcase 2014-09-09 17:48:36 +02:00
Christian Geier
753e730906 bugfix: save password with host in keyring
(the same way we try to recover it)
2014-09-09 14:10:37 +02:00
Markus Unterwaditzer
f9f1e37655 Properly mark a wart in code. 2014-09-06 01:51:36 +02:00
Markus Unterwaditzer
9e12e29db6 Properly deal with invalid filename characters
Fix #110
2014-09-03 20:35:31 +02:00
Markus Unterwaditzer
3d39526531 Allow file arg on netrc mock
On my machine, requests is trying to access it for some reason
2014-09-03 19:13:20 +02:00
Markus Unterwaditzer
add9f640b4 CalDAV: Explicitly exclude items
Excluding items without mimetype "text/calendar" becomes necessary when
listing items, because iCloud would re-send us the URL we issued the
REPORT request on, a collection, with a mimetype of
"httpd/unix-directory".

    debug: REPORT https://p28-caldav.icloud.com/8010146223/calendars/home/
    debug: {'Depth': 'infinity', 'Content-Type': 'application/xml; charset=UTF-8', 'User-Agent': 'vdirsyncer '}
    debug: <?xml version="1.0" encoding="utf-8" ?>
    debug:             <C:calendar-query xmlns:D="DAV:"
    debug:                 xmlns:C="urn:ietf:params:xml:ns:caldav">
    debug:                 <D:prop>
    debug:                     <D:getetag/>
    debug:                 </D:prop>
    debug:                 <C:filter>
    debug:
    debug:                 <C:comp-filter name="VCALENDAR">
    debug:                     <C:comp-filter name="VTODO">
    debug:
    debug:                     </C:comp-filter>
    debug:                 </C:comp-filter>
    debug:
    debug:                 </C:filter>
    debug:             </C:calendar-query>
    debug: Sending request...
    debug: 207
    debug: {'content-encoding': 'gzip', 'transfer-encoding': 'chunked', 'server': 'iCloudCalendarServer 14F4 1', 'last-modified': 'Tue, 02 Sep 2014 13:59:11 GMT', 'dav': '1, access-control, calendar-access, calend ar-schedule, calendar-auto-schedule, calendar-managed-attachments, calendarserver-sharing, calendarserve r-subscribed, calendarserver-home-sync', 'x-transaction-id': '7f311996-32b4-11e4-a6db-78e3b5058dc0', 'da te': 'Tue, 02 Sep 2014 15:19:13 GMT', 'x-responding-server': 'mr21p28ic-hpaf05163701 18 a63660a6f7d1a25b 5a7ed66dab0da843', 'content-type': 'text/xml'}
    debug: <?xml version='1.0' encoding='UTF-8'?><multistatus xmlns='DAV:'>
    debug:
    debug:   <response>
    debug:     <href>/8010146223/calendars/home/</href>
    debug:     <propstat>
    debug:       <prop>
    debug:          <getetag>"FT=-@RU=301785db-0889-442c-ab5d-03144258969a@S=30"</getetag>
    debug:         <getcontenttype>httpd/unix-directory</getcontenttype>
    debug:       </prop>
    debug:       <status>HTTP/1.1 200 OK</status>
    debug:     </propstat>
    debug:   </response>
    debug:
    debug:   <response>
    debug:     <href>/8010146223/calendars/home/412580F4-7A0A-480D-BA99-73260B921E5D.ics</href>
    debug:     <propstat>
    debug:       <prop>
    debug:         <getetag>"C=30@U=301785db-0889-442c-ab5d-03144258969a"</getetag>
    debug:         <getcontenttype>text/calendar</getcontenttype>
    ...
2014-09-02 17:25:09 +02:00
Markus Unterwaditzer
4426fbc1d3 Merge pull request #109 from geier/master
README: build.sh command names changed
2014-09-01 17:44:40 +02:00
Christian Geier
406392db5d README: build.sh command names changed 2014-09-01 17:43:27 +02:00
Markus Unterwaditzer
686441b5ab Merge pull request #106 from untitaker/tls_fingerprints
TLS fingerprints (2.1)
2014-08-30 18:59:26 +02:00
Markus Unterwaditzer
0bc03666ba Fix dead doubleclick testcase
click.CliRunner swallowed all exceptions, also AssertionError
2014-08-30 17:06:01 +02:00
Markus Unterwaditzer
2bbc92534d Some sync refactoring
- Use only one dict for storing all temporary state of a storage
- Rename functions to be internal
2014-08-30 16:23:27 +02:00
Thomas Weißschuh
fa2f7ca540 always serve something, else werkzeug blows up 2014-08-29 18:44:23 +00:00
Thomas Weißschuh
23ae6eb03f we need the git version of werkzeug for ssl support on py3 2014-08-29 17:24:27 +00:00
Markus Unterwaditzer
69505f4c61 Fix link again 2014-08-27 17:46:04 +02:00
Markus Unterwaditzer
7e606f6123 Update link 2014-08-27 17:42:13 +02:00
Markus Unterwaditzer
b3e6f22518 Version 0.2.5 2014-08-27 14:06:55 +02:00
Markus Unterwaditzer
96b1c08804 doubleclick: sanity check re multiple contexts 2014-08-26 00:43:44 +02:00
Markus Unterwaditzer
c78ac67ba9 Merge pull request #107 from untitaker/reuse_passwords
Reuse passwords
2014-08-24 19:55:44 +02:00
Markus Unterwaditzer
f6088fd036 Give up on proper signal handling 2014-08-23 10:37:42 +02:00
Markus Unterwaditzer
ed6d75f1db Add locks for click.confirm
I assumed click.confirm uses click.prompt, but it doesn't (version 3.1)
2014-08-22 20:06:37 +02:00
Markus Unterwaditzer
c7e6acc0ba Rewrite get_password
Only fetching by hostname, no bruteforce algorithm for system keyring
2014-08-22 20:06:37 +02:00
Markus Unterwaditzer
25843580e0 Switch to threading 2014-08-22 20:06:37 +02:00
Markus Unterwaditzer
f5a701a920 Create global context 2014-08-22 13:06:22 +02:00
Markus Unterwaditzer
9816e0140d Require click>=3.1
See https://github.com/mitsuhiko/click/issues/200
2014-08-21 17:38:52 +02:00
Markus Unterwaditzer
b093989220 Refine testcase again 2014-08-21 01:26:00 +02:00
Markus Unterwaditzer
63c990a320 Properly remove monkeypatching in radicale tests 2014-08-21 00:56:13 +02:00
Markus Unterwaditzer
b909d525f8 Fix broken testcase 2014-08-21 00:51:25 +02:00
Markus Unterwaditzer
e8e55de165 Add some tests 2014-08-21 00:26:48 +02:00
Thomas Weißschuh
f61ef5318d remove superfluous method override 2014-08-20 22:04:35 +00:00
Markus Unterwaditzer
44c1d84a7e Fix style errors 2014-08-21 00:01:17 +02:00
Markus Unterwaditzer
c9c2a43f43 Rename tls_fingerprint to verify_fingerprint 2014-08-20 23:39:26 +02:00
Markus Unterwaditzer
5509868958 Revert "Revert "Tls fingerprints"" 2014-08-20 18:43:34 +02:00
Markus Unterwaditzer
d30437b8fe Merge pull request #104 from untitaker/revert-102-tls_fingerprints
Revert "Tls fingerprints"
2014-08-20 18:39:11 +02:00
Markus Unterwaditzer
c86ad88c96 Revert "Tls fingerprints" 2014-08-20 18:38:59 +02:00
Markus Unterwaditzer
ec708ea273 Fix typo 2014-08-19 23:04:33 +02:00
Markus Unterwaditzer
eb0833e180 Make CI scripts more readable. 2014-08-19 22:56:40 +02:00
Markus Unterwaditzer
d0a2331d86 Don't produce overlapping output or prompts.
See #96 and #101
2014-08-19 15:54:25 +02:00
Markus Unterwaditzer
73b8381ab8 Merge pull request #102 from t-8ch/tls_fingerprints
Tls fingerprints

Fix #100
2014-08-18 23:51:23 +02:00
Thomas Weißschuh
8c77c57d4c document tls_fingerprint 2014-08-18 21:08:11 +00:00
Thomas Weißschuh
0de3102c2c add tls_fingerprint to storage.dav.DavStorage 2014-08-18 21:02:46 +00:00
Thomas Weißschuh
c9cfd0f1ed s/CONTRIBUTORS.rst/AUTHORS.rst/ 2014-08-18 19:21:00 +00:00
Thomas Weißschuh
9d034b7ed6 add myself to AUTHORS.rst 2014-08-18 19:20:25 +00:00
Thomas Weißschuh
cd72de610a add tls_fingerprint support to the http backend 2014-08-18 19:18:30 +00:00
Thomas Weißschuh
af06e24f45 enable tls_fingerprint for the dav backend 2014-08-18 19:18:30 +00:00
Thomas Weißschuh
56d566e55a add a tls_prefix parameter to utils.request
This assumes that a backend only ever connects to a single domain, because we
set the fingerprint on the whole session
2014-08-18 19:17:55 +00:00
Thomas Weißschuh
d5e8be4979 [tests] directly monkeypatch requests Session
need for later changes
2014-08-18 19:11:07 +00:00
Markus Unterwaditzer
a321038a1d Don't try to show pretty error messages for ^C 2014-08-18 18:39:19 +02:00
Markus Unterwaditzer
bb4939bfdb Validate general section.
Fix #100
2014-08-18 18:33:58 +02:00
Markus Unterwaditzer
ea756175d3 Raise proper error messages when using discovery
Init arg introspection didn't properly occur when the user used
collection discovery to create the storages. Instead the raw exception
from the inside of s.discover bubbled up.
2014-08-18 17:13:15 +02:00
Markus Unterwaditzer
226006f985 Actually check for dav_headers 2014-08-18 17:12:45 +02:00
Markus Unterwaditzer
cef25b58da Version 0.2.4 2014-08-18 12:45:50 +02:00
Markus Unterwaditzer
4af6da43ef Include metadata and doc files in distribution
Fix #98
Fix #97
2014-08-18 12:35:32 +02:00
Markus Unterwaditzer
8ea3b82c50 Add assertion for CLI output 2014-08-18 01:03:34 +02:00
Markus Unterwaditzer
1fff7efff5 Use name from config for representing storages 2014-08-18 00:53:05 +02:00
Markus Unterwaditzer
2fd4aaead3 Add tests for prepare_auth 2014-08-15 18:29:11 +02:00
Markus Unterwaditzer
8414d654d3 Rename CONTRIBUTORS to AUTHORS
Easy to confuse when skimming through the tree.

But the real reason (for me) is that the tab-completion is not very
useful when two files start with the same prefix.
2014-08-14 19:56:35 +02:00
Markus Unterwaditzer
d9c2b7ba35 Don't emit collections twice 2014-08-13 17:19:25 +02:00
Markus Unterwaditzer
a741b5d639 I hope this helps more servers than just Radicale 2014-08-13 13:44:52 +02:00
Markus Unterwaditzer
5051e8949a Code deduplication 2014-08-13 00:46:15 +02:00
Markus Unterwaditzer
9f26c6450c Version 0.2.3 2014-08-11 16:42:31 +02:00
Markus Unterwaditzer
39472b9db4 Update CONTRIBUTING.rst 2014-08-07 18:37:32 +02:00
Markus Unterwaditzer
2e2082fb55 Make _create_bogus_item a fixture.
Also rename the "storage" fixture to "get_storage".
2014-08-06 22:03:30 +02:00
Markus Unterwaditzer
6841b25264 Add --version flag, fix #92 2014-08-06 17:47:58 +02:00
Markus Unterwaditzer
05d2beb3dc Merge pull request #93 from untitaker/href_quoting
Fix all known URL-quoting related problems
2014-08-06 17:25:37 +02:00
Markus Unterwaditzer
eb1431e5db Fix all known URL-quoting problems
- Fix #49 -- The old fix caused problems with other servers. The new
  behavior only decodes ``@`` characters.

- ``@`` is now not used when generating a new href, as some servers seem
  to have problems with it (http://sabre.io/dav/character-encoding/).
  This behavior is configurable via the ``unsafe_href_chars`` parameters
  for DAV storages, and is disabled in the testsuite for Radicale and
  ownCloud.

- Decoding of hrefs is also done twice for CarddavStorage.list because
  of owncloud/contacts#581. Vdirsyncer has behaved like that before, but
  not intentionally.

- Storages now don't share their ``_get_href`` methods anymore.
2014-08-06 16:43:23 +02:00
148 changed files with 13835 additions and 4547 deletions

View file

@ -0,0 +1,49 @@
# Run tests using the packaged dependencies on ArchLinux.
image: archlinux
packages:
- docker
- docker-compose
# Build dependencies:
- python-wheel
- python-build
- python-installer
- python-setuptools-scm
# Runtime dependencies:
- python-click
- python-click-log
- python-click-threading
- python-requests
- python-aiohttp-oauthlib
- python-tenacity
# Test dependencies:
- python-hypothesis
- python-pytest-cov
- python-pytest-httpserver
- python-trustme
- python-pytest-asyncio
- python-aiohttp
- python-aiostream
- python-aioresponses
sources:
- https://github.com/pimutils/vdirsyncer
environment:
BUILD: test
CI: true
CODECOV_TOKEN: b834a3c5-28fa-4808-9bdb-182210069c79
DAV_SERVER: radicale xandikos
REQUIREMENTS: release
# TODO: ETESYNC_TESTS
tasks:
- check-python:
python --version | grep 'Python 3.13'
- docker: |
sudo systemctl start docker
- setup: |
cd vdirsyncer
python -m build --wheel --skip-dependency-check --no-isolation
sudo python -m installer dist/*.whl
- test: |
cd vdirsyncer
make -e ci-test
make -e ci-test-storage

36
.builds/tests-minimal.yml Normal file
View file

@ -0,0 +1,36 @@
# Run tests using oldest available dependency versions.
#
# TODO: It might make more sense to test with an older Ubuntu or Fedora version
# here, and consider that our "oldest suppported environment".
image: alpine/3.19 # python 3.11
packages:
- docker
- docker-cli
- docker-compose
- py3-pip
- python3-dev
sources:
- https://github.com/pimutils/vdirsyncer
environment:
BUILD: test
CI: true
CODECOV_TOKEN: b834a3c5-28fa-4808-9bdb-182210069c79
DAV_SERVER: radicale xandikos
REQUIREMENTS: minimal
tasks:
- venv: |
python3 -m venv $HOME/venv
echo "export PATH=$HOME/venv/bin:$PATH" >> $HOME/.buildenv
- docker: |
sudo addgroup $(whoami) docker
sudo service docker start
- setup: |
cd vdirsyncer
# Hack, no idea why it's needed
sudo ln -s /usr/include/python3.11/cpython/longintrepr.h /usr/include/python3.11/longintrepr.h
make -e install-dev
- test: |
cd vdirsyncer
make -e ci-test
make -e ci-test-storage

45
.builds/tests-pypi.yml Normal file
View file

@ -0,0 +1,45 @@
# Run tests using latest dependencies from PyPI
image: archlinux
packages:
- docker
- docker-compose
- python-pip
sources:
- https://github.com/pimutils/vdirsyncer
secrets:
- 4d9a6dfe-5c8d-48bd-b864-a2f5d772c536
environment:
BUILD: test
CI: true
CODECOV_TOKEN: b834a3c5-28fa-4808-9bdb-182210069c79
DAV_SERVER: baikal radicale xandikos
REQUIREMENTS: release
# TODO: ETESYNC_TESTS
tasks:
- venv: |
python -m venv $HOME/venv
echo "export PATH=$HOME/venv/bin:$PATH" >> $HOME/.buildenv
- docker: |
sudo systemctl start docker
- setup: |
cd vdirsyncer
make -e install-dev
- test: |
cd vdirsyncer
make -e ci-test
make -e ci-test-storage
- check: |
cd vdirsyncer
make check
- check-secrets: |
# Stop here if this is a PR. PRs can't run with the below secrets.
[ -f ~/fastmail-secrets ] || complete-build
- extra-storages: |
set +x
source ~/fastmail-secrets
set -x
cd vdirsyncer
export PATH=$PATH:~/.local/bin/
DAV_SERVER=fastmail pytest tests/storage

4
.codecov.yml Normal file
View file

@ -0,0 +1,4 @@
comment: false
coverage:
status:
patch: false

22
.coveragerc Normal file
View file

@ -0,0 +1,22 @@
[run]
branch = True
[paths]
source = vdirsyncer/
[report]
exclude_lines =
# Have to re-enable the standard pragma
pragma: no cover
# Don't complain about missing debug-only code:
def __repr__
if self\.debug
# Don't complain if tests don't hit defensive assertion code:
raise AssertionError
raise NotImplementedError
# Don't complain if non-runnable code isn't run:
if 0:
if __name__ == .__main__.:

1
.envrc Normal file
View file

@ -0,0 +1 @@
layout python3

9
.gitignore vendored
View file

@ -6,9 +6,12 @@ build
env env
*.egg-info *.egg-info
.cache .cache
.pytest_cache
.eggs
.egg
.xprocess .xprocess
dist dist
tests/storage/dav/servers/*
!tests/storage/dav/servers/__init__.py
!tests/storage/dav/servers/radicale
docs/_build/ docs/_build/
vdirsyncer/version.py
.hypothesis
coverage.xml

39
.pre-commit-config.yaml Normal file
View file

@ -0,0 +1,39 @@
repos:
- repo: https://github.com/pre-commit/pre-commit-hooks
rev: v5.0.0
hooks:
- id: trailing-whitespace
args: [--markdown-linebreak-ext=md]
- id: end-of-file-fixer
- id: check-toml
- id: check-added-large-files
- id: debug-statements
- repo: https://github.com/pre-commit/mirrors-mypy
rev: "v1.15.0"
hooks:
- id: mypy
files: vdirsyncer/.*
additional_dependencies:
- types-setuptools
- types-docutils
- types-requests
- repo: https://github.com/charliermarsh/ruff-pre-commit
rev: 'v0.11.4'
hooks:
- id: ruff
args: [--fix, --exit-non-zero-on-fix]
- id: ruff-format
- repo: local
hooks:
- id: typos-syncroniz
name: typos-syncroniz
language: system
# Not how you spell "synchronise"
entry: sh -c "git grep -i syncroniz"
files: ".*/.*"
- id: typos-text-icalendar
name: typos-text-icalendar
language: system
# It's "text/calendar", no "i".
entry: sh -c "git grep -i 'text/icalendar'"
files: ".*/.*"

16
.readthedocs.yaml Normal file
View file

@ -0,0 +1,16 @@
version: 2
sphinx:
configuration: docs/conf.py
build:
os: "ubuntu-22.04"
tools:
python: "3.9"
python:
install:
- method: pip
path: .
extra_requirements:
- docs

View file

@ -1,18 +0,0 @@
language: python
python:
- "2.7"
- "3.3"
- "3.4"
env:
- BUILD=tests DAV_SERVER=radicale RADICALE_BACKEND=filesystem REQUIREMENTS=release
- BUILD=tests DAV_SERVER=radicale RADICALE_BACKEND=filesystem REQUIREMENTS=release PKGS='icalendar==3.6'
- BUILD=tests DAV_SERVER=radicale RADICALE_BACKEND=filesystem REQUIREMENTS=devel
- BUILD=tests DAV_SERVER=radicale RADICALE_BACKEND=database REQUIREMENTS=devel
- BUILD=tests DAV_SERVER=owncloud REQUIREMENTS=release
- BUILD=style
install:
- "./build.sh install"
- '[ -z "$PKGS" ] || pip install $PKGS'
script:
- "./build.sh run"

29
AUTHORS.rst Normal file
View file

@ -0,0 +1,29 @@
Contributors
============
In alphabetical order:
- Ben Boeckel
- Bleala
- Christian Geier
- Clément Mondon
- Corey Hinshaw
- Kai Herlemann
- Hugo Osvaldo Barrera
- Jason Cox
- Julian Mehne
- Malte Kiefer
- Marek Marczykowski-Górecki
- Markus Unterwaditzer
- Michael Adler
- rEnr3n
- Thomas Weißschuh
- Witcher01
- samm81
Special thanks goes to:
* `FastMail <https://github.com/pimutils/vdirsyncer/issues/571>`_ sponsors a
paid account for testing their servers.
* `Packagecloud <https://packagecloud.io/>`_ provide repositories for
vdirsyncer's Debian packages.

View file

@ -5,6 +5,696 @@ Changelog
This changelog only contains information that might be useful to end users and This changelog only contains information that might be useful to end users and
package maintainers. For further info, see the git commit log. package maintainers. For further info, see the git commit log.
Package maintainers and users who have to manually update their installation
may want to subscribe to `GitHub's tag feed
<https://github.com/pimutils/vdirsyncer/tags.atom>`_.
Version 0.21.0
==============
- Implement retrying for ``google`` storage type when a rate limit is reached.
- ``tenacity`` is now a required dependency.
- Drop support for Python 3.8.
- Retry transient network errors for nullipotent requests.
Version 0.20.0
==============
- Remove dependency on abandoned ``atomicwrites`` library.
- Implement ``filter_hook`` for the HTTP storage.
- Drop support for Python 3.7.
- Add support for Python 3.12 and Python 3.13.
- Properly close the status database after using. This especially affects tests,
where we were leaking a large amount of file descriptors.
- Extend supported versions of ``aiostream`` to include 0.7.x.
Version 0.19.3
==============
- Added a no_delete option to the storage configuration. :gh:`1090`
- Fix crash when running ``vdirsyncer repair`` on a collection. :gh:`1019`
- Add an option to request vCard v4.0. :gh:`1066`
- Require matching ``BEGIN`` and ``END`` lines in vobjects. :gh:`1103`
- A Docker environment for Vdirsyncer has been added `Vdirsyncer DOCKERIZED <https://github.com/Bleala/Vdirsyncer-DOCKERIZED>`_.
- Implement digest auth. :gh:`1137`
- Add ``filter_hook`` parameter to :storage:`http`. :gh:`1136`
Version 0.19.2
==============
- Improve the performance of ``SingleFileStorage``. :gh:`818`
- Properly document some caveats of the Google Contacts storage.
- Fix crash when using auth certs. :gh:`1033`
- The ``filesystem`` storage can be specified with ``type =
"filesystem/icalendar"`` or ``type = "filesystem/vcard"``. This has not
functional impact, and is merely for forward compatibility with the Rust
implementation of vdirsyncer.
- Python 3.10 and 3.11 are officially supported.
- Instructions for integrating with Google CalDav/CardDav have changed.
Applications now need to be registered as "Desktop applications". Using "Web
application" no longer works due to changes on Google's side. :gh:`1078`
Version 0.19.1
==============
- Fixed crash when operating on Google Contacts. :gh:`994`
- The ``HTTP_PROXY`` and ``HTTPS_PROXY`` are now respected. :gh:`1031`
- Instructions for integrating with Google CalDav/CardDav have changed.
Applications now need to be registered as "Web Application". :gh:`975`
- Various documentation updates.
Version 0.19.0
==============
- Add "shell" password fetch strategy to pass command string to a shell.
- Add "description" and "order" as metadata. These fetch the CalDAV:
calendar-description, ``CardDAV:addressbook-description`` and
``apple-ns:calendar-order`` properties respectively.
- Add a new ``showconfig`` status. This prints *some* configuration values as
JSON. This is intended to be used by external tools and helpers that interact
with ``vdirsyncer``, and considered experimental.
- Add ``implicit`` option to the :ref:`pair section <pair_config>`. When set to
"create", it implicitly creates missing collections during sync without user
prompts. This simplifies workflows where collections should be automatically
created on both sides.
- Update TLS-related tests that were failing due to weak MDs. :gh:`903`
- ``pytest-httpserver`` and ``trustme`` are now required for tests.
- ``pytest-localserver`` is no longer required for tests.
- Multithreaded support has been dropped. The ``"--max-workers`` has been removed.
- A new ``asyncio`` backend is now used. So far, this shows substantial speed
improvements in ``discovery`` and ``metasync``, but little change in `sync`.
This will likely continue improving over time. :gh:`906`
- The ``google`` storage types no longer require ``requests-oauthlib``, but
require ``python-aiohttp-oauthlib`` instead.
- Vdirsyncer no longer includes experimental support for `EteSync
<https://www.etesync.com/>`_. The existing integration had not been supported
for a long time and no longer worked. Support for external storages may be
added if anyone is interested in maintaining an EteSync plugin. EteSync
users should consider using `etesync-dav`_.
- The ``plist`` for macOS has been dropped. It was broken and homebrew
generates their own based on package metadata. macOS users are encouraged to
use that as a reference.
.. _etesync-dav: https://github.com/etesync/etesync-dav
Changes to SSL configuration
----------------------------
Support for ``md5`` and ``sha1`` certificate fingerprints has been dropped. If
you're validating certificate fingerprints, use ``sha256`` instead.
When using a custom ``verify_fingerprint``, CA validation is always disabled.
If ``verify_fingerprint`` is unset, CA verification is always active. Disabling
both features is insecure and no longer supported.
The ``verify`` parameter no longer takes boolean values, it is now optional and
only takes a string to a custom CA for verification.
The ``verify`` and ``verify_fingerprint`` will likely be merged into a single
parameter in future.
Version 0.18.0
==============
Note: Version 0.17 has some alpha releases but ultimately was never finalised.
0.18 actually continues where 0.16 left off.
- Support for Python 3.5 and 3.6 has been dropped. This release mostly focuses
on keeping vdirsyncer compatible with newer environments.
- click 8 and click-threading 0.5.0 are now required.
- For those using ``pipsi``, we now recommend using ``pipx``, it's successor.
- Python 3.9 is now supported.
- Our Debian/Ubuntu build scripts have been updated. New versions should be
pushed to those repositories soon.
Version 0.16.8
==============
*released 09 June 2020*
- Support Python 3.7 and 3.8.
This release is functionally identical to 0.16.7.
It's been tested with recent Python versions, and has been marked as supporting
them. It will also be the final release supporting Python 3.5 and 3.6.
Version 0.16.7
==============
*released on 19 July 2018*
- Fixes for Python 3.7
Version 0.16.6
==============
*released on 13 June 2018*
- **Packagers:** Documentation building no longer needs a working installation
of vdirsyncer.
Version 0.16.5
==============
*released on 13 June 2018*
- **Packagers:** click-log 0.3 is required.
- All output will now happen on stderr (because of the upgrade of ``click-log``).
Version 0.16.4
==============
*released on 05 February 2018*
- Fix tests for new Hypothesis version. (Literally no other change included)
Version 0.16.3
==============
*released on 03 October 2017*
- First version with custom Debian and Ubuntu packages. See :gh:`663`.
- Remove invalid ASCII control characters from server responses. See :gh:`626`.
- **packagers:** Python 3.3 is no longer supported. See :ghpr:`674`.
Version 0.16.2
==============
*released on 24 August 2017*
- Fix crash when using daterange or item_type filters in
:storage:`google_calendar`, see :gh:`657`.
- **Packagers:** Fixes for new version ``0.2.0`` of ``click-log``. The version
requirements for the dependency ``click-log`` changed.
Version 0.16.1
==============
*released on 8 August 2017*
- Removed remoteStorage support, see :gh:`647`.
- Fixed test failures caused by latest requests version, see :gh:`660`.
Version 0.16.0
==============
*released on 2 June 2017*
- Strip ``METHOD:PUBLISH`` added by some calendar providers, see :gh:`502`.
- Fix crash of Google storages when saving token file.
- Make DAV discovery more RFC-conformant, see :ghpr:`585`.
- Vdirsyncer is now tested against Xandikos, see :ghpr:`601`.
- Subfolders with a leading dot are now ignored during discover for
``filesystem`` storage. This makes it easier to combine it with version
control.
- Statuses are now stored in a sqlite database. Old data is automatically
migrated. Users with really large datasets should encounter performance
improvements. This means that **sqlite3 is now a dependency of vdirsyncer**.
- **Vdirsyncer is now licensed under the 3-clause BSD license**, see :gh:`610`.
- Vdirsyncer now includes experimental support for `EteSync
<https://www.etesync.com/>`_, see :ghpr:`614`.
- Vdirsyncer now uses more filesystem metadata for determining whether an item
changed. You will notice a **possibly heavy CPU/IO spike on the first sync
after upgrading**.
- **Packagers:** Reference ``systemd.service`` and ``systemd.timer`` unit files
are provided. It is recommended to install these as documentation if your
distribution is systemd-based.
Version 0.15.0
==============
*released on 28 February 2017*
- Deprecated syntax for configuration values is now completely rejected. All
values now have to be valid JSON.
- A few UX improvements for Google storages, see :gh:`549` and :gh:`552`.
- Fix collection discovery for :storage:`google_contacts`, see :gh:`564`.
- iCloud is now tested on Travis, see :gh:`567`.
Version 0.14.1
==============
*released on 05 January 2017*
- ``vdirsyncer repair`` no longer changes "unsafe" UIDs by default, an extra
option has to be specified. See :gh:`527`.
- A lot of important documentation updates.
Version 0.14.0
==============
*released on 26 October 2016*
- ``vdirsyncer sync`` now continues other uploads if one upload failed. The
exit code in such situations is still non-zero.
- Add ``partial_sync`` option to pair section. See :ref:`the config docs
<partial_sync_def>`.
- Vdirsyncer will now warn if there's a string without quotes in your config.
Please file issues if you find documentation that uses unquoted strings.
- Fix an issue that would break khal's config setup wizard.
Version 0.13.1
==============
*released on 30 September 2016*
- Fix a bug that would completely break collection discovery.
Version 0.13.0
==============
*released on 29 September 2016*
- Python 2 is no longer supported at all. See :gh:`219`.
- Config sections are now checked for duplicate names. This also means that you
cannot have a storage section ``[storage foo]`` and a pair ``[pair foo]`` in
your config, they have to have different names. This is done such that
console output is always unambiguous. See :gh:`459`.
- Custom commands can now be used for conflict resolution during sync. See
:gh:`127`.
- :storage:`http` now completely ignores UIDs. This avoids a lot of unnecessary
down- and uploads.
Version 0.12.1
==============
*released on 20 August 2016*
- Fix a crash for Google and DAV storages. See :ghpr:`492`.
- Fix an URL-encoding problem with DavMail. See :gh:`491`.
Version 0.12
============
*released on 19 August 2016*
- :storage:`singlefile` now supports collections. See :ghpr:`488`.
Version 0.11.3
==============
*released on 29 July 2016*
- Default value of ``auth`` parameter was changed from ``guess`` to ``basic``
to resolve issues with the Apple Calendar Server (:gh:`457`) and improve
performance. See :gh:`461`.
- **Packagers:** The ``click-threading`` requirement is now ``>=0.2``. It was
incorrect before. See :gh:`478`.
- Fix a bug in the DAV XML parsing code that would make vdirsyncer crash on
certain input. See :gh:`480`.
- Redirect chains should now be properly handled when resolving ``well-known``
URLs. See :ghpr:`481`.
Version 0.11.2
==============
*released on 15 June 2016*
- Fix typo that would break tests.
Version 0.11.1
==============
*released on 15 June 2016*
- Fix a bug in collection validation.
- Fix a cosmetic bug in debug output.
- Various documentation improvements.
Version 0.11.0
==============
*released on 19 May 2016*
- Discovery is no longer automatically done when running ``vdirsyncer sync``.
``vdirsyncer discover`` now has to be explicitly called.
- Add a ``.plist`` example for Mac OS X.
- Usage under Python 2 now requires a special config parameter to be set.
- Various deprecated configuration parameters do no longer have specialized
errormessages. The generic error message for unknown parameters is shown.
- Vdirsyncer no longer warns that the ``passwordeval`` parameter has been
renamed to ``password_command``.
- The ``keyring`` fetching strategy has been dropped some versions ago, but
the specialized error message has been dropped.
- An old status format from version 0.4 is no longer supported. If you're
experiencing problems, just delete your status folder.
Version 0.10.0
==============
*released on 23 April 2016*
- New storage types :storage:`google_calendar` and :storage:`google_contacts`
have been added.
- New global command line option `--config`, to specify an alternative config
file. See :gh:`409`.
- The ``collections`` parameter can now be used to synchronize
differently-named collections with each other.
- **Packagers:** The ``lxml`` dependency has been dropped.
- XML parsing is now a lot stricter. Malfunctioning servers that used to work
with vdirsyncer may stop working.
Version 0.9.3
=============
*released on 22 March 2016*
- :storage:`singlefile` and :storage:`http` now handle recurring events
properly.
- Fix a typo in the packaging guidelines.
- Moved to ``pimutils`` organization on GitHub. Old links *should* redirect,
but be aware of client software that doesn't properly handle redirects.
Version 0.9.2
=============
*released on 13 March 2016*
- Fixed testsuite for environments that don't have any web browser installed.
See :ghpr:`384`.
Version 0.9.1
=============
*released on 13 March 2016*
- Removed leftover debug print statement in ``vdirsyncer discover``, see commit
``3d856749f37639821b148238ef35f1acba82db36``.
- ``metasync`` will now strip whitespace from the start and the end of the
values. See :gh:`358`.
- New ``Packaging Guidelines`` have been added to the documentation.
Version 0.9.0
=============
*released on 15 February 2016*
- The ``collections`` parameter is now required in pair configurations.
Vdirsyncer will tell you what to do in its error message. See :gh:`328`.
Version 0.8.1
=============
*released on 30 January 2016*
- Fix error messages when invalid parameter fetching strategy is used. This is
important because users would receive awkward errors for using deprecated
``keyring`` fetching.
Version 0.8.0
=============
*released on 27 January 2016*
- Keyring support has been removed, which means that ``password.fetch =
["keyring", "example.com", "myuser"]`` doesn't work anymore.
For existing setups: Use ``password.fetch = ["command", "keyring", "get",
"example.com", "myuser"]`` instead, which is more generic. See the
documentation for details.
- Now emitting a warning when running under Python 2. See :gh:`219`.
Version 0.7.5
=============
*released on 23 December 2015*
- Fixed a bug in :storage:`remotestorage` that would try to open a CLI browser
for OAuth.
- Fix a packaging bug that would prevent vdirsyncer from working with newer
lxml versions.
Version 0.7.4
=============
*released on 22 December 2015*
- Improved error messages instead of faulty server behavior, see :gh:`290` and
:gh:`300`.
- Safer shutdown of threadpool, avoid exceptions, see :gh:`291`.
- Fix a sync bug for read-only storages see commit
``ed22764921b2e5bf6a934cf14aa9c5fede804d8e``.
- Etag changes are no longer sufficient to trigger sync operations. An actual
content change is also necessary. See :gh:`257`.
- :storage:`remotestorage` now automatically opens authentication dialogs in
your configured GUI browser.
- **Packagers:** ``lxml>=3.1`` is now required (newer lower-bound version).
Version 0.7.3
=============
*released on 05 November 2015*
- Make remotestorage-dependencies actually optional.
Version 0.7.2
=============
*released on 05 November 2015*
- Un-break testsuite.
Version 0.7.1
=============
*released on 05 November 2015*
- **Packagers:** The setuptools extras ``keyring`` and ``remotestorage`` have
been added. They're basically optional dependencies. See ``setup.py`` for
more details.
- Highly experimental remoteStorage support has been added. It may be
completely overhauled or even removed in any version.
- Removed mentions of old ``password_command`` in documentation.
Version 0.7.0
=============
*released on 27 October 2015*
- **Packagers:** New dependencies are ``click_threading``, ``click_log`` and
``click>=5.0``.
- ``password_command`` is gone. Keyring support got completely overhauled. See
:doc:`keyring`.
Version 0.6.0
=============
*released on 06 August 2015*
- ``password_command`` invocations with non-zero exit code are now fatal (and
will abort synchronization) instead of just producing a warning.
- Vdirsyncer is now able to synchronize metadata of collections. Set ``metadata
= ["displayname"]`` and run ``vdirsyncer metasync``.
- **Packagers:** Don't use the GitHub tarballs, but the PyPI ones.
- **Packagers:** ``build.sh`` is gone, and ``Makefile`` is included in
tarballs. See the content of ``Makefile`` on how to run tests post-packaging.
- ``verify_fingerprint`` doesn't automatically disable ``verify`` anymore.
Version 0.5.2
=============
*released on 15 June 2015*
- Vdirsyncer now checks and corrects the permissions of status files.
- Vdirsyncer is now more robust towards changing UIDs inside items.
- Vdirsyncer is now handling unicode hrefs and UIDs correctly. Software that
produces non-ASCII UIDs is broken, but apparently it exists.
Version 0.5.1
=============
*released on 29 May 2015*
- **N.b.: The PyPI upload of 0.5.0 is completely broken.**
- Raise version of required requests-toolbelt to ``0.4.0``.
- Command line should be a lot faster when no work is done, e.g. for help
output.
- Fix compatibility with iCloud again.
- Use only one worker if debug mode is activated.
- ``verify=false`` is now disallowed in vdirsyncer, please use
``verify_fingerprint`` instead.
- Fixed a bug where vdirsyncer's DAV storage was not using the configured
useragent for collection discovery.
Version 0.4.4
=============
*released on 12 March 2015*
- Support for client certificates via the new ``auth_cert``
parameter, see :gh:`182` and :ghpr:`183`.
- The ``icalendar`` package is no longer required.
- Several bugfixes related to collection creation.
Version 0.4.3
=============
*released on 20 February 2015*
- More performance improvements to ``singlefile``-storage.
- Add ``post_hook`` param to ``filesystem``-storage.
- Collection creation now also works with SabreDAV-based servers, such as
Baikal or ownCloud.
- Removed some workarounds for Radicale. Upgrading to the latest Radicale will
fix the issues.
- Fixed issues with iCloud discovery.
- Vdirsyncer now includes a simple ``repair`` command that seeks to fix some
broken items.
Version 0.4.2
=============
*released on 30 January 2015*
- Vdirsyncer now respects redirects when uploading and updating items. This
might fix issues with Zimbra.
- Relative ``status_path`` values are now interpreted as relative to the
configuration file's directory.
- Fixed compatibility with custom SabreDAV servers. See :gh:`166`.
- Catch harmless threading exceptions that occur when shutting down vdirsyncer.
See :gh:`167`.
- Vdirsyncer now depends on ``atomicwrites``.
- Massive performance improvements to ``singlefile``-storage.
- Items with extremely long UIDs should now be saved properly in
``filesystem``-storage. See :gh:`173`.
Version 0.4.1
=============
*released on 05 January 2015*
- All ``create`` arguments from all storages are gone. Vdirsyncer now asks if
it should try to create collections.
- The old config values ``True``, ``False``, ``on``, ``off`` and ``None`` are
now invalid.
- UID conflicts are now properly handled instead of ignoring one item. Card-
and CalDAV servers are already supposed to take care of those though.
- Official Baikal support added.
Version 0.4.0
=============
*released on 31 December 2014*
- The ``passwordeval`` parameter has been renamed to ``password_command``.
- The old way of writing certain config values such as lists is now gone.
- Collection discovery has been rewritten. Old configuration files should be
compatible with it, but vdirsyncer now caches the results of the collection
discovery. You have to run ``vdirsyncer discover`` if collections were added
or removed on one side.
- Pair and storage names are now restricted to certain characters. Vdirsyncer
will issue a clear error message if your configuration file is invalid in
that regard.
- Vdirsyncer now supports the XDG-Basedir specification. If the
``VDIRSYNCER_CONFIG`` environment variable isn't set and the
``~/.vdirsyncer/config`` file doesn't exist, it will look for the
configuration file at ``$XDG_CONFIG_HOME/vdirsyncer/config``.
- Some improvements to CardDAV and CalDAV discovery, based on problems found
with FastMail. Support for ``.well-known``-URIs has been added.
Version 0.3.4
=============
*released on 8 December 2014*
- Some more bugfixes to config handling.
Version 0.3.3
=============
*released on 8 December 2014*
- Vdirsyncer now also works with iCloud. Particularly collection discovery and
etag handling were fixed.
- Vdirsyncer now encodes Cal- and CardDAV requests differently. This hasn't
been well-tested with servers like Zimbra or SoGo, but isn't expected to
cause any problems.
- Vdirsyncer is now more robust regarding invalid responses from CalDAV
servers. This should help with future compatibility with Davmail/Outlook.
- Fix a bug when specifying ``item_types`` of :storage:`caldav` in the
deprecated config format.
- Fix a bug where vdirsyncer would ignore all but one character specified in
``unsafe_href_chars`` of :storage:`caldav` and :storage:`carddav`.
Version 0.3.2
=============
*released on 3 December 2014*
- The current config format has been deprecated, and support for it will be
removed in version 0.4.0. Vdirsyncer warns about this now.
Version 0.3.1
=============
*released on 24 November 2014*
- Fixed a bug where vdirsyncer would delete items if they're deleted on side A
but modified on side B. Instead vdirsyncer will now upload the new items to
side A. See :gh:`128`.
- Synchronization continues with the remaining pairs if one pair crashes, see
:gh:`121`.
- The ``processes`` config key is gone. There is now a ``--max-workers`` option
on the CLI which has a similar purpose. See :ghpr:`126`.
- The Read The Docs-theme is no longer required for building the docs. If it is
not installed, the default theme will be used. See :gh:`134`.
Version 0.3.0
=============
*released on 20 September 2014*
- Add ``verify_fingerprint`` parameter to :storage:`http`, :storage:`caldav`
and :storage:`carddav`, see :gh:`99` and :ghpr:`106`.
- Add ``passwordeval`` parameter to :ref:`general_config`, see :gh:`108` and
:ghpr:`117`.
- Emit warnings (instead of exceptions) about certain invalid responses from
the server, see :gh:`113`. This is apparently required for compatibility
with Davmail.
Version 0.2.5
=============
*released on 27 August 2014*
- Don't ask for the password of one server more than once and fix multiple
concurrency issues, see :gh:`101`.
- Better validation of DAV endpoints.
Version 0.2.4
=============
*released on 18 August 2014*
- Include workaround for collection discovery with latest version of Radicale.
- Include metadata files such as the changelog or license in source
distribution, see :gh:`97` and :gh:`98`.
Version 0.2.3
=============
*released on 11 August 2014*
- Vdirsyncer now has a ``--version`` flag, see :gh:`92`.
- Fix a lot of bugs related to special characters in URLs, see :gh:`49`.
Version 0.2.2 Version 0.2.2
============= =============
@ -12,16 +702,12 @@ Version 0.2.2
- Remove a security check that caused problems with special characters in DAV - Remove a security check that caused problems with special characters in DAV
URLs and certain servers. On top of that, the security check was nonsensical. URLs and certain servers. On top of that, the security check was nonsensical.
See issues `#87`_ and `#91`_. See :gh:`87` and :gh:`91`.
- Change some errors to warnings, see issue `#88`_. - Change some errors to warnings, see :gh:`88`.
- Improve collection autodiscovery for servers without full support. - Improve collection autodiscovery for servers without full support.
.. _`#87`: https://github.com/untitaker/vdirsyncer/issues/87
.. _`#88`: https://github.com/untitaker/vdirsyncer/issues/88
.. _`#91`: https://github.com/untitaker/vdirsyncer/issues/91
Version 0.2.1 Version 0.2.1
============= =============
@ -51,8 +737,7 @@ Version 0.2.0
instead of the proper etag would have been returned from the upload method. instead of the proper etag would have been returned from the upload method.
vdirsyncer might do unnecessary copying when upgrading to this version. vdirsyncer might do unnecessary copying when upgrading to this version.
- Add the storage :py:class:`vdirsyncer.storage.SingleFileStorage`. See issue - Add the storage :storage:`singlefile`. See :gh:`48`.
`#48`_.
- The ``collections`` parameter for pair sections now accepts the special - The ``collections`` parameter for pair sections now accepts the special
values ``from a`` and ``from b`` for automatically discovering collections. values ``from a`` and ``from b`` for automatically discovering collections.
@ -61,8 +746,6 @@ Version 0.2.0
- The ``read_only`` parameter was added to storage sections. See - The ``read_only`` parameter was added to storage sections. See
:ref:`storage_config`. :ref:`storage_config`.
.. _`#48`: https://github.com/untitaker/vdirsyncer/issues/48
Version 0.1.5 Version 0.1.5
============= =============
@ -77,6 +760,4 @@ Version 0.1.5
- vdirsyncer now doesn't necessarily need UIDs anymore for synchronization. - vdirsyncer now doesn't necessarily need UIDs anymore for synchronization.
- vdirsyncer now aborts if one collection got completely emptied between - vdirsyncer now aborts if one collection got completely emptied between
synchronizations. See `#42`_. synchronizations. See :gh:`42`.
.. _`#42`: https://github.com/untitaker/vdirsyncer/issues/42

1
CODE_OF_CONDUCT.rst Normal file
View file

@ -0,0 +1 @@
See `the pimutils CoC <http://pimutils.org/coc>`_.

View file

@ -1,28 +1,3 @@
* If you're reporting an issue with vdirsyncer: Please see `the documentation
<https://vdirsyncer.pimutils.org/en/stable/contributing.html>`_ for how to
* Make sure you have the latest version by executing ``pip install --user contribute to this project.
--upgrade vdirsyncer``.
* Include the Python version, your configuration, the commands you're
executing, and their output.
* Use ``--verbosity=DEBUG`` when including output from vdirsyncer.
* If you're suggesting a feature, keep in mind that vdirsyncer tries not to be
a full calendar or contacts client, but rather just the piece of software
that synchronizes all the data. If you're looking for a viewer for the
calendar data you've synced, `khal <https://github.com/geier/khal>`_ is what
you're looking for.
* If you're submitting pull requests:
* Make sure your tests pass on Travis.
* But not because you wrote too few tests.
* Write descriptive commit messages, mostly because i need to write a
changelog at some point. Use ``git rebase -i`` and ``git commit --ammend``
if needed.
* Add yourself to ``CONTRIBUTORS.rst`` and also add an entry to
``CHANGELOG.rst`` if you think your change is relevant to end users.

View file

@ -1,9 +0,0 @@
Contributors
============
In alphabetical order:
- Christian Geier
- Clément Mondon
- Julian Mehne
- Markus Unterwaditzer

12
ISSUE_TEMPLATE.md Normal file
View file

@ -0,0 +1,12 @@
Before you submit bug reports: https://vdirsyncer.pimutils.org/en/stable/contributing.html
Things to include in your bugreport:
* Your vdirsyncer version
* If applicable, which server software (and which version) you're using
* Your Python version
* Your operating system
* Your config file
* Use `vdirsyncer -vdebug` for debug output. The output is sensitive, but
please attach at least the last few lines before the error (if applicable),
censored as necessary. This is almost always the most useful information.

46
LICENSE
View file

@ -1,19 +1,33 @@
Copyright (c) 2014 Markus Unterwaditzer & contributors Copyright (c) 2014-2020 by Markus Unterwaditzer & contributors. See
AUTHORS.rst for more details.
Permission is hereby granted, free of charge, to any person obtaining a copy of Some rights reserved.
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 Redistribution and use in source and binary forms of the software as well
copies or substantial portions of the Software. as documentation, with or without modification, are permitted provided
that the following conditions are met:
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * Redistributions of source code must retain the above copyright
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, notice, this list of conditions and the following disclaimer.
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * Redistributions in binary form must reproduce the above
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, copyright notice, this list of conditions and the following
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE disclaimer in the documentation and/or other materials provided
SOFTWARE. with the distribution.
* The names of the contributors may not be used to endorse or
promote products derived from this software without specific
prior written permission.
THIS SOFTWARE AND DOCUMENTATION IS PROVIDED BY THE COPYRIGHT HOLDERS AND
CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT
NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE AND DOCUMENTATION, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
DAMAGE.

9
MANIFEST.in Normal file
View file

@ -0,0 +1,9 @@
# setuptools-scm includes everything tracked by git
prune docker
prune scripts
prune tests/storage/servers
recursive-include tests/storage/servers/radicale *
recursive-include tests/storage/servers/skip *
prune docs/_build
global-exclude *.py[cdo] __pycache__ *.so *.pyd

63
Makefile Normal file
View file

@ -0,0 +1,63 @@
# See the documentation on how to run the tests:
# https://vdirsyncer.pimutils.org/en/stable/contributing.html
# Which DAV server to run the tests against (radicale, xandikos, skip, owncloud, nextcloud, ...)
export DAV_SERVER := skip
# release (install release versions of dependencies)
# development (install development versions of some of vdirsyncer's dependencies)
# or minimal (install oldest version of each dependency that is supported by vdirsyncer)
export REQUIREMENTS := release
# Set this to true if you run vdirsyncer's test as part of e.g. packaging.
export DETERMINISTIC_TESTS := false
# Assume to run in CI. Don't use this outside of a virtual machine. It will
# heavily "pollute" your system, such as attempting to install a new Python
# systemwide.
export CI := false
# Whether to generate coverage data while running tests.
export COVERAGE := $(CI)
# Variables below this line are not very interesting for getting started.
CODECOV_PATH = /tmp/codecov.sh
all:
$(error Take a look at https://vdirsyncer.pimutils.org/en/stable/tutorial.html#installation)
ci-test:
curl -s https://codecov.io/bash > $(CODECOV_PATH)
pytest --cov vdirsyncer --cov-append tests/unit/ tests/system/
bash $(CODECOV_PATH) -c
ci-test-storage:
curl -s https://codecov.io/bash > $(CODECOV_PATH)
set -ex; \
for server in $(DAV_SERVER); do \
DAV_SERVER=$$server pytest --cov vdirsyncer --cov-append tests/storage; \
done
bash $(CODECOV_PATH) -c
check:
ruff check
ruff format --diff
#mypy vdirsyncer
release-deb:
sh scripts/release-deb.sh debian jessie
sh scripts/release-deb.sh debian stretch
sh scripts/release-deb.sh ubuntu trusty
sh scripts/release-deb.sh ubuntu xenial
sh scripts/release-deb.sh ubuntu zesty
install-dev:
pip install -U pip setuptools wheel
pip install -e '.[test,check,docs]'
set -xe && if [ "$(REQUIREMENTS)" = "minimal" ]; then \
pip install pyproject-dependencies && \
pip install -U --force-reinstall $$(pyproject-dependencies . | sed 's/>/=/'); \
fi
.PHONY: docs

View file

@ -2,37 +2,73 @@
vdirsyncer vdirsyncer
========== ==========
vdirsyncer synchronizes your calendars and addressbooks between two storages. .. image:: https://builds.sr.ht/~whynothugo/vdirsyncer.svg
The supported storages are CalDAV, CardDAV, arbitrary HTTP resources and `some :target: https://builds.sr.ht/~whynothugo/vdirsyncer
more <https://vdirsyncer.readthedocs.org/en/latest/api.html#storages>`_. :alt: CI status
It aims to be for CalDAV and CardDAV what `OfflineIMAP .. image:: https://codecov.io/github/pimutils/vdirsyncer/coverage.svg?branch=main
<http://offlineimap.org/>`_ is for IMAP. :target: https://codecov.io/github/pimutils/vdirsyncer?branch=main
:alt: Codecov coverage report
.. image:: https://travis-ci.org/untitaker/vdirsyncer.png?branch=master .. image:: https://readthedocs.org/projects/vdirsyncer/badge/
:target: https://travis-ci.org/untitaker/vdirsyncer :target: https://vdirsyncer.rtfd.org/
:alt: documentation
.. image:: https://coveralls.io/repos/untitaker/vdirsyncer/badge.png?branch=master .. image:: https://img.shields.io/pypi/v/vdirsyncer.svg
:target: https://coveralls.io/r/untitaker/vdirsyncer?branch=master :target: https://pypi.python.org/pypi/vdirsyncer
:alt: version on pypi
How to use .. image:: https://img.shields.io/badge/deb-packagecloud.io-844fec.svg
========== :target: https://packagecloud.io/pimutils/vdirsyncer
:alt: Debian packages
vdirsyncer requires Python >= 2.7 or Python >= 3.3. .. image:: https://img.shields.io/pypi/l/vdirsyncer.svg
:target: https://github.com/pimutils/vdirsyncer/blob/main/LICENCE
:alt: licence: BSD
As all Python packages, vdirsyncer can be installed with ``pip``:: - `Documentation <https://vdirsyncer.pimutils.org/en/stable/>`_
- `Source code <https://github.com/pimutils/vdirsyncer>`_
pip install --user vdirsyncer Vdirsyncer is a command-line tool for synchronizing calendars and addressbooks
between a variety of servers and the local filesystem. The most popular usecase
is to synchronize a server with a local folder and use a set of other programs_
to change the local events and contacts. Vdirsyncer can then synchronize those
changes back to the server.
Then copy ``example.cfg`` to ``~/.vdirsyncer/config`` and edit it. However, vdirsyncer is not limited to synchronizing between clients and
servers. It can also be used to synchronize calendars and/or addressbooks
between two servers directly.
Run ``vdirsyncer --help`` and check out `the documentation It aims to be for calendars and contacts what `OfflineIMAP
<https://vdirsyncer.readthedocs.org/>`_. <https://www.offlineimap.org/>`_ is for emails.
How to run the tests .. _programs: https://vdirsyncer.pimutils.org/en/latest/tutorials/
====================
:: Links of interest
=================
sh build.sh install * Check out `the tutorial
sh build.sh run <https://vdirsyncer.pimutils.org/en/stable/tutorial.html>`_ for basic
usage.
* `Contact information
<https://vdirsyncer.pimutils.org/en/stable/contact.html>`_
* `How to contribute to this project
<https://vdirsyncer.pimutils.org/en/stable/contributing.html>`_
* `Donations <https://vdirsyncer.pimutils.org/en/stable/donations.html>`_
Dockerized
=================
If you want to run `Vdirsyncer <https://vdirsyncer.pimutils.org/en/stable/>`_ in a
Docker environment, you can check out the following GitHub Repository:
* `Vdirsyncer DOCKERIZED <https://github.com/Bleala/Vdirsyncer-DOCKERIZED>`_
Note: This is an unofficial Docker build, it is maintained by `Bleala <https://github.com/Bleala>`_.
License
=======
Licensed under the 3-clause BSD license, see ``LICENSE``.

View file

@ -1,90 +0,0 @@
#!/bin/sh
set -e
_davserver() {
# Maybe tmpfs is mounted on /tmp/, can't harm anyway.
if [ ! -d $TESTSERVER_BASE$1/ ]; then
git clone --depth=1 \
https://github.com/vdirsyncer/$1-testserver.git \
/tmp/$1-testserver
ln -s /tmp/$1-testserver $TESTSERVER_BASE$1
fi
(cd $TESTSERVER_BASE$1 && sh install.sh)
}
install_build_tests() {
$PIP_INSTALL \
coverage \
pytest \
pytest-xprocess
_davserver $DAV_SERVER
if [ "$TRAVIS" = "true" ]; then
export CFLAGS=-O0 # speed up builds of packages which don't have wheels
$PIP_INSTALL --upgrade pip
$PIP_INSTALL wheel
PIP_INSTALL="pip install --use-wheel --find-links=http://travis-wheels.unterwaditzer.net/wheels/"
$PIP_INSTALL coveralls
fi
$PIP_INSTALL --editable .
}
run_build_tests() {
if [ "$TRAVIS" = "true" ]; then
coverage run --source=vdirsyncer/,tests/ --module pytest
coveralls
else
py.test
fi
}
install_build_style() {
$PIP_INSTALL flake8
}
run_build_style() {
flake8 vdirsyncer tests
! git grep -il syncroniz $(ls | grep -v 'build.sh')
}
install_build_docs() {
$PIP_INSTALL sphinx sphinx_rtd_theme
$PIP_INSTALL -e .
}
run_build_docs() {
cd docs
make html
}
[ -n "$BUILD" ] || BUILD=tests
[ -n "$DAV_SERVER" ] || DAV_SERVER=radicale
[ -n "$REQUIREMENTS" ] || REQUIREMENTS=release
COMMAND="$1"
if [ -z "$COMMAND" ]; then
echo "Usage:"
echo "build.sh run # run build"
echo "build.sh install # install dependencies"
echo
echo "Environment variable combinations:"
echo "BUILD=tests # install and run tests"
echo " # (using Radicale, see .travis.yml for more)"
echo "BUILD=style # install and run stylechecker (flake8)"
echo "BUILD=docs # install sphinx and build HTML docs"
exit 1
fi
TESTSERVER_BASE=./tests/storage/dav/servers/
install_builds() {
echo "Installing for $BUILD"
PIP_INSTALL="pip install"
install_build_$BUILD
}
run_builds() {
echo "Running $BUILD"
run_build_$BUILD
}
${COMMAND}_builds

70
config.example Normal file
View file

@ -0,0 +1,70 @@
# An example configuration for vdirsyncer.
#
# Move it to ~/.vdirsyncer/config or ~/.config/vdirsyncer/config and edit it.
# Run `vdirsyncer --help` for CLI usage.
#
# Optional parameters are commented out.
# This file doesn't document all available parameters, see
# http://vdirsyncer.pimutils.org/ for the rest of them.
[general]
# A folder where vdirsyncer can store some metadata about each pair.
status_path = "~/.vdirsyncer/status/"
# CARDDAV
[pair bob_contacts]
# A `[pair <name>]` block defines two storages `a` and `b` that should be
# synchronized. The definition of these storages follows in `[storage <name>]`
# blocks. This is similar to accounts in OfflineIMAP.
a = "bob_contacts_local"
b = "bob_contacts_remote"
# Synchronize all collections that can be found.
# You need to run `vdirsyncer discover` if new calendars/addressbooks are added
# on the server.
collections = ["from a", "from b"]
# Synchronize the "display name" property into a local file (~/.contacts/displayname).
metadata = ["displayname"]
# To resolve a conflict the following values are possible:
# `null` - abort when collisions occur (default)
# `"a wins"` - assume a's items to be more up-to-date
# `"b wins"` - assume b's items to be more up-to-date
#conflict_resolution = null
[storage bob_contacts_local]
# A storage references actual data on a remote server or on the local disk.
# Similar to repositories in OfflineIMAP.
type = "filesystem"
path = "~/.contacts/"
fileext = ".vcf"
[storage bob_contacts_remote]
type = "carddav"
url = "https://owncloud.example.com/remote.php/carddav/"
#username =
# The password can also be fetched from the system password storage, netrc or a
# custom command. See http://vdirsyncer.pimutils.org/en/stable/keyring.html
#password =
# CALDAV
[pair bob_calendar]
a = "bob_calendar_local"
b = "bob_calendar_remote"
collections = ["from a", "from b"]
# Calendars also have a color property
metadata = ["displayname", "color"]
[storage bob_calendar_local]
type = "filesystem"
path = "~/.calendars/"
fileext = ".ics"
[storage bob_calendar_remote]
type = "caldav"
url = "https://owncloud.example.com/remote.php/caldav/"
#username =
#password =

View file

@ -0,0 +1,75 @@
#!/usr/bin/env python3
"""Ask user to resolve a vdirsyncer sync conflict interactively.
Needs a way to ask the user.
The use of https://apps.kde.org/kdialog/ for GNU/Linix is hardcoded.
Depends on python>3.5 and KDialog.
Usage:
Ensure the file executable and use it in the vdirsyncer.conf file, e.g.
conflict_resolution = ["command", "/home/bern/vdirsyncer/resolve_interactively.py"]
This file is Free Software under the following license:
SPDX-License-Identifier: BSD-3-Clause
SPDX-FileCopyrightText: 2021 Intevation GmbH <https://intevation.de>
Author: <bernhard.reiter@intevation.de>
"""
from __future__ import annotations
import re
import subprocess
import sys
from pathlib import Path
KDIALOG = "/usr/bin/kdialog"
SUMMARY_PATTERN = re.compile("^(SUMMARY:.*)$", re.MULTILINE)
def get_summary(icalendar_text: str):
"""Get the first SUMMARY: line from an iCalendar text.
Do not care about the line being continued.
"""
match = re.search(SUMMARY_PATTERN, icalendar_text)
return match[1]
def main(ical1_filename, ical2_filename):
ical1 = ical1_filename.read_text()
ical2 = ical2_filename.read_text()
additional_args = ["--yes-label", "take first"] # return code == 0
additional_args += ["--no-label", "take second"] # return code == 1
additional_args += ["--cancel-label", "do not resolve"] # return code == 2
r = subprocess.run(
args=[
KDIALOG,
"--warningyesnocancel",
"There was a sync conflict, do you prefer the first entry: \n"
f"{get_summary(ical1)}...\n(full contents: {ical1_filename})\n\n"
"or the second entry:\n"
f"{get_summary(ical2)}...\n(full contents: {ical2_filename})?",
*additional_args,
]
)
if r.returncode == 2:
# cancel was pressed
return # shall lead to items not changed, because not copied
if r.returncode == 0:
# we want to take the first item, so overwrite the second
ical2_filename.write_text(ical1)
else: # r.returncode == 1, we want the second item, so overwrite the first
ical1_filename.write_text(ical2)
if len(sys.argv) != 3:
sys.stdout.write(__doc__)
else:
main(Path(sys.argv[1]), Path(sys.argv[2]))

View file

@ -0,0 +1,9 @@
[Unit]
Description=Synchronize calendars and contacts
Documentation=https://vdirsyncer.readthedocs.org/
StartLimitBurst=2
[Service]
ExecStart=/usr/bin/vdirsyncer sync
RuntimeMaxSec=3m
Restart=on-failure

10
contrib/vdirsyncer.timer Normal file
View file

@ -0,0 +1,10 @@
[Unit]
Description=Synchronize vdirs
[Timer]
OnBootSec=5m
OnUnitActiveSec=15m
AccuracySec=5m
[Install]
WantedBy=timers.target

0
docs/_static/.gitkeep vendored Normal file
View file

View file

@ -1,113 +0,0 @@
===
API
===
Config Parameters
=================
.. _general_config:
General Section
---------------
::
[general]
status_path = ...
#processes = 0
- ``status_path``: A directory where vdirsyncer will store metadata for the
next sync. The data is needed to determine whether a new item means it has
been added on one side or deleted on the other.
- ``processes``: Optional, defines the amount of maximal connections to use for
syncing. By default there is no limit, which means vdirsyncer will try to
open a connection for each collection to be synced. The value ``0`` is
ignored. Setting this to ``1`` will only synchronize one collection at a
time.
While this often greatly increases performance, you might have valid reasons
to set this to a smaller number. For example, your DAV server running on a
Raspberry Pi is so slow that multiple connections don't help much, since the
CPU and not the network is the bottleneck.
.. _pair_config:
Pair Section
------------
::
[pair pair_name]
a = ...
b = ...
#conflict_resolution = ...
- ``a`` and ``b`` reference the storages to sync by their names.
- ``collections``: Optional, a comma-separated list of collections to
synchronize. If this parameter is omitted, it is assumed the storages are
already directly pointing to one collection each. Specifying a collection
multiple times won't make vdirsyncer sync that collection more than once.
Furthermore, there are the special values ``from a`` and ``from b``, which
tell vdirsyncer to try autodiscovery on a specific storage::
collections = from b,foo,bar # all in storage b + "foo" + "bar"
collections = from b,from a # all in storage a + all in storage b
- ``conflict_resolution``: Optional, define how conflicts should be handled. A
conflict occurs when one item changed on both sides since the last sync.
Valid values are ``a wins`` and ``b wins``. By default, vdirsyncer will show
an error and abort the synchronization.
.. _storage_config:
Storage Section
---------------
::
[storage storage_name]
type = ...
- ``type`` defines which kind of storage is defined. See :ref:`storages`.
- ``read_only`` defines whether the storage should be regarded as a read-only
storage. The value ``True`` means synchronization will discard any changes
made to the other side. The value ``False`` implies normal 2-way
synchronization.
- Any further parameters are passed on to the storage class.
.. _storages:
Supported Storages
==================
.. module:: vdirsyncer.storage
Read-write storages
-------------------
These storages generally support reading and changing of their items. Their
default value for ``read_only`` is ``False``, but can be set to ``True`` if
wished.
.. autoclass:: CaldavStorage
.. autoclass:: CarddavStorage
.. autoclass:: FilesystemStorage
.. autoclass:: SingleFileStorage
Read-only storages
------------------
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
leads to an error.
.. autoclass:: HttpStorage

View file

@ -1 +1 @@
.. include:: ../CHANGELOG.rst .. include:: ../CHANGELOG.rst

View file

@ -1,58 +1,106 @@
# -*- coding: utf-8 -*- from __future__ import annotations
import datetime
import os import os
import sys
import pkg_resources from pkg_resources import get_distribution
extensions = ['sphinx.ext.autodoc'] extensions = ["sphinx.ext.autodoc"]
templates_path = ['_templates'] templates_path = ["_templates"]
source_suffix = '.rst' source_suffix = ".rst"
master_doc = 'index' master_doc = "index"
project = u'vdirsyncer' project = "vdirsyncer"
copyright = u'2014, Markus Unterwaditzer & contributors' copyright = "2014-{}, Markus Unterwaditzer & contributors".format(
datetime.date.today().strftime("%Y")
)
release = get_distribution("vdirsyncer").version
version = ".".join(release.split(".")[:2]) # The short X.Y version.
rst_epilog = f".. |vdirsyncer_version| replace:: {release}"
exclude_patterns = ["_build"]
pygments_style = "sphinx"
on_rtd = os.environ.get("READTHEDOCS", None) == "True"
try: try:
# The full version, including alpha/beta/rc tags.
release = pkg_resources.require('vdirsyncer')[0].version
except pkg_resources.DistributionNotFound:
print('To build the documentation, the distribution information of'
'vdirsyncer has to be available. Run "setup.py develop" to do'
'this.')
sys.exit(1)
version = '.'.join(release.split('.')[:2]) # The short X.Y version.
exclude_patterns = ['_build']
pygments_style = 'sphinx'
on_rtd = os.environ.get('READTHEDOCS', None) == 'True'
if not on_rtd:
import sphinx_rtd_theme import sphinx_rtd_theme
html_theme = 'sphinx_rtd_theme'
html_theme_path = [sphinx_rtd_theme.get_html_theme_path()]
html_static_path = ['_static'] html_theme = "sphinx_rtd_theme"
htmlhelp_basename = 'vdirsyncerdoc' html_theme_path = [sphinx_rtd_theme.get_html_theme_path()]
except ImportError:
html_theme = "default"
if not on_rtd:
print("-" * 74)
print("Warning: sphinx-rtd-theme not installed, building with default theme.")
print("-" * 74)
html_static_path = ["_static"]
htmlhelp_basename = "vdirsyncerdoc"
latex_elements = {} latex_elements = {}
latex_documents = [ latex_documents = [
('index', 'vdirsyncer.tex', u'vdirsyncer Documentation', (
u'Markus Unterwaditzer', 'manual'), "index",
"vdirsyncer.tex",
"vdirsyncer Documentation",
"Markus Unterwaditzer",
"manual",
),
] ]
man_pages = [ man_pages = [
('index', 'vdirsyncer', u'vdirsyncer Documentation', ("index", "vdirsyncer", "vdirsyncer Documentation", ["Markus Unterwaditzer"], 1)
[u'Markus Unterwaditzer'], 1)
] ]
texinfo_documents = [ texinfo_documents = [
('index', 'vdirsyncer', u'vdirsyncer Documentation', (
u'Markus Unterwaditzer', 'vdirsyncer', "index",
'One line description of project.', 'Miscellaneous'), "vdirsyncer",
"vdirsyncer Documentation",
"Markus Unterwaditzer",
"vdirsyncer",
"Synchronize calendars and contacts.",
"Miscellaneous",
),
] ]
def github_issue_role(name, rawtext, text, lineno, inliner, options=None, content=()):
options = options or {}
try:
issue_num = int(text)
if issue_num <= 0:
raise ValueError
except ValueError:
msg = inliner.reporter.error(f"Invalid GitHub issue: {text}", line=lineno)
prb = inliner.problematic(rawtext, rawtext, msg)
return [prb], [msg]
from docutils import nodes
PROJECT_HOME = "https://github.com/pimutils/vdirsyncer"
link = "{}/{}/{}".format(
PROJECT_HOME, "issues" if name == "gh" else "pull", issue_num
)
linktext = ("issue #{}" if name == "gh" else "pull request #{}").format(issue_num)
node = nodes.reference(rawtext, linktext, refuri=link, **options)
return [node], []
def setup(app):
from sphinx.domains.python import PyObject
app.add_object_type(
"storage",
"storage",
"pair: %s; storage",
doc_field_types=PyObject.doc_field_types,
)
app.add_role("gh", github_issue_role)
app.add_role("ghpr", github_issue_role)

526
docs/config.rst Normal file
View file

@ -0,0 +1,526 @@
=========================
Full configuration manual
=========================
Vdirsyncer uses an ini-like format for storing its configuration. All values
are JSON, invalid JSON will get interpreted as string::
x = "foo" # String
x = foo # Shorthand for same string
x = 42 # Integer
x = ["a", "b", "c"] # List of strings
x = true # Boolean
x = false
x = null # Also known as None
.. _general_config:
General Section
===============
::
[general]
status_path = ...
- ``status_path``: A directory where vdirsyncer will store some additional data
for the next sync.
The data is needed to determine whether a new item means it has been added on
one side or deleted on the other. Relative paths will be interpreted as
relative to the configuration file's directory.
See `A simple synchronization algorithm
<https://unterwaditzer.net/2016/sync-algorithm.html>`_ for what exactly is in
there.
.. _pair_config:
Pair Section
============
::
[pair pair_name]
a = ...
b = ...
#collections = null
#conflict_resolution = null
- Pair names can consist of any alphanumeric characters and the underscore.
- ``a`` and ``b`` reference the storages to sync by their names.
- ``collections``: A list of collections to synchronize when ``vdirsyncer
sync`` is executed. See also :ref:`collections_tutorial`.
The special values ``"from a"`` and ``"from b"``, tell vdirsyncer to try
autodiscovery on a specific storage. It means all the collections on side A /
side B.
If the collection you want to sync doesn't have the same name on each side,
you may also use a value of the form ``["config_name", "name_a", "name_b"]``.
This will synchronize the collection ``name_a`` on side A with the collection
``name_b`` on side B. The ``config_name`` will be used for representation in
CLI arguments and logging.
Examples:
- ``collections = ["from b", "foo", "bar"]`` makes vdirsyncer synchronize all
the collections from side B, and also the collections named "foo" and "bar".
- ``collections = ["from b", "from a"]`` makes vdirsyncer synchronize all
existing collections on either side.
- ``collections = [["bar", "bar_a", "bar_b"], "foo"]`` makes vdirsyncer
synchronize ``bar_a`` from side A with ``bar_b`` from side B, and also
synchronize ``foo`` on both sides with each other.
- ``conflict_resolution``: Optional, define how conflicts should be handled. A
conflict occurs when one item (event, task) changed on both sides since the
last sync. See also :ref:`conflict_resolution_tutorial`.
Valid values are:
- ``null``, where an error is shown and no changes are done.
- ``"a wins"`` and ``"b wins"``, where the whole item is taken from one side.
- ``["command", "vimdiff"]``: ``vimdiff <a> <b>`` will be called where
``<a>`` and ``<b>`` are temporary files that contain the item of each side
respectively. The files need to be exactly the same when the command
returns.
- ``vimdiff`` can be replaced with any other command. For example, in POSIX
``["command", "cp"]`` is equivalent to ``"a wins"``.
- Additional list items will be forwarded as arguments. For example,
``["command", "vimdiff", "--noplugin"]`` runs ``vimdiff --noplugin``.
Vdirsyncer never attempts to "automatically merge" the two items.
.. _partial_sync_def:
- ``partial_sync``: Assume A is read-only, B not. If you change items on B,
vdirsyncer can't sync the changes to A. What should happen instead?
- ``error``: An error is shown.
- ``ignore``: The change is ignored. However: Events deleted in B still
reappear if they're updated in A.
- ``revert`` (default): The change is reverted on next sync.
See also :ref:`partial_sync_tutorial`.
- ``metadata``: Metadata keys that should be synchronized when ``vdirsyncer
metasync`` is executed. Example::
metadata = ["color", "displayname", "description", "order"]
This synchronizes the following properties:
- color: ``http://apple.com/ns/ical/:calendar-color``
- displayname: ``DAV:displayname``
- description: ``CalDAV:calendar-description`` and ``CardDAV:addressbook-description``
- order: ``http://apple.com/ns/ical/:calendar-order``
The ``conflict_resolution`` parameter applies for these properties too.
.. _implicit_def:
- ``implicit``: Opt into implicitly creating collections. Example::
implicit = "create"
When set to "create", missing collections are automatically created on both
sides during sync without prompting the user. This simplifies workflows where
all collections should be synchronized bidirectionally.
.. _storage_config:
Storage Section
===============
::
[storage storage_name]
type = ...
- Storage names can consist of any alphanumeric characters and the underscore.
- ``type`` defines which kind of storage is defined. See :ref:`storages`.
- ``read_only`` defines whether the storage should be regarded as a read-only
storage. The value ``true`` means synchronization will discard any changes
made to the other side. The value ``false`` implies normal 2-way
synchronization.
- Any further parameters are passed on to the storage class.
.. _storages:
Supported Storages
------------------
CalDAV and CardDAV
++++++++++++++++++
.. note::
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 = /path/to/custom_ca.pem
#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: Optional. Local path to a self-signed SSL certificate.
See :ref:`ssl-tutorial` for more information.
:param verify_fingerprint: Optional. SHA256 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 = /path/to/custom_ca.pem
#auth = null
#useragent = "vdirsyncer/0.16.4"
#verify_fingerprint = null
#auth_cert = null
#use_vcard_4 = false
:param url: Base URL or an URL to an addressbook.
:param username: Username for authentication.
:param password: Password for authentication.
:param verify: Optional. Local path to a self-signed SSL certificate.
See :ref:`ssl-tutorial` for more information.
:param verify_fingerprint: Optional. SHA256 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``.
:param use_vcard_4: Whether the server use vCard 4.0.
Google
++++++
Vdirsyncer supports synchronization with Google calendars with the restriction
that ``VTODO`` files are rejected by the server.
Synchronization with Google contacts is less reliable due to negligence of
Google's CardDAV API. **Google's CardDAV implementation is allegedly a disaster
in terms of data safety**. See `this blog post
<https://evertpot.com/google-carddav-issues/>`_ for the details. Always back
up your data.
Another caveat is that Google group labels are not synced with vCard's
`CATEGORIES <https://www.rfc-editor.org/rfc/rfc6350#section-6.7.1>`_ property
(also see :gh:`814` and
`upstream issue #36761530 <https://issuetracker.google.com/issues/36761530>`_
for reference) and the
`BDAY <https://www.rfc-editor.org/rfc/rfc6350#section-6.2.5>`_ property is not
synced when only partial date information is present (e.g. the year is missing).
At first run you will be asked to authorize application for Google account
access.
To use this storage type, you need to install some additional dependencies::
pip install vdirsyncer[google]
Furthermore you need to register vdirsyncer as an application yourself to
obtain ``client_id`` and ``client_secret``, as it is against Google's Terms of
Service to hardcode those into opensource software [googleterms]_:
1. Go to the `Google API Manager <https://console.developers.google.com>`_
2. Create a new project under any name.
2. Within that project, enable the "CalDAV" and "CardDAV" APIs (**not** the
Calendar and Contacts APIs, those are different and won't work). There should
be a search box where you can just enter those terms.
3. In the sidebar, select "Credentials", then "Create Credentials" and create a
new "OAuth Client ID".
You'll be prompted to create a OAuth consent screen first. Fill out that
form however you like.
After setting up the consent screen, finish creating the new "OAuth Client
ID'. The correct application type is "Desktop application".
4. Finally you should have a Client ID and a Client secret. Provide these in
your storage config.
The ``token_file`` parameter should be a path to a file where vdirsyncer can
later store authentication-related data. You do not need to create the file
itself or write anything to it.
.. [googleterms] See `ToS <https://developers.google.com/terms/?hl=th>`_,
section "Confidential Matters".
.. note::
You need to configure which calendars Google should offer vdirsyncer using
a secret `settings page
<https://calendar.google.com/calendar/syncselect>`_.
.. storage:: google_calendar
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.
The current flow is not ideal, but Google has deprecated the previous APIs used
for this without providing a suitable replacement. See :gh:`975` for discussion
on the topic.
Local
+++++
.. storage:: filesystem
Saves each item in its own file, given a directory.
::
[storage example_for_filesystem]
type = "filesystem"
path = "..."
fileext = "..."
#encoding = "utf-8"
#post_hook = null
#pre_deletion_hook = null
#fileignoreext = ".tmp"
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). To be compatible with the ``vset`` format you have
to either use ``.vcf`` or ``.ics``. Note that metasync won't work
if you use an empty string here.
: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.
:param pre_deletion_hook: A command to call for each item deletion.
The command will be called with the path of the deleted file.
:param fileeignoreext: The file extention to ignore. It is only useful
if fileext is set to the empty string. The default is ``.tmp``.
.. 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
++++++++++++++++++
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
leads to an error.
.. 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
#filter_hook = null
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: Optional. Local path to a self-signed SSL certificate.
See :ref:`ssl-tutorial` for more information.
:param verify_fingerprint: Optional. SHA256 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``.
:param filter_hook: Optional. A filter command to call for each fetched
item, passed in raw form to stdin and returned via stdout.
If nothing is returned by the filter command, the item is skipped.
This can be used to alter fields as needed when dealing with providers
generating malformed events.

12
docs/contact.rst Normal file
View file

@ -0,0 +1,12 @@
===================
Support and Contact
===================
* The ``#pimutils`` `IRC channel on Libera.Chat <https://pimutils.org/contact>`_
might be active, depending on your timezone. Use it for support and general
(including off-topic) discussion.
* Open `a GitHub issue <https://github.com/pimutils/vdirsyncer/issues/>`_ for
concrete bug reports and feature requests.
* For security issues, contact ``contact@pimutils.org``.

127
docs/contributing.rst Normal file
View file

@ -0,0 +1,127 @@
============================
Contributing to this project
============================
.. note::
- Please read :doc:`contact` for questions and support requests.
- All participants must follow the `pimutils Code of Conduct
<http://pimutils.org/coc>`_.
The issue tracker
=================
We use `GitHub issues <https://github.com/pimutils/vdirsyncer/issues>`_ for
organizing bug reports and feature requests.
The following `labels <https://github.com/pimutils/vdirsyncer/labels>`_ are of
interest:
* "Planning" is for issues that are still undecided, but where at least some
discussion exists.
* "Blocked" is for issues that can't be worked on at the moment because some
other unsolved problem exists. This problem may be a bug in some software
dependency, for instance.
* "Ready" contains issues that are ready to work on.
If you just want to get started with contributing, the "ready" issues are an
option. Issues that are still in "Planning" are also an option, but require
more upfront thinking and may turn out to be impossible to solve, or at least
harder than anticipated. On the flip side those tend to be the more interesting
issues as well, depending on how one looks at it.
All of those labels are also available as a kanban board on `waffle.io
<https://waffle.io/pimutils/vdirsyncer>`_. It is really just an alternative
overview over all issues, but might be easier to comprehend.
Feel free to :doc:`contact <contact>` me or comment on the relevant issues for
further information.
Reporting bugs
--------------
* Make sure your problem isn't already listed in :doc:`problems`.
* Make sure you have the absolutely latest version of vdirsyncer. For users of
some Linux distributions such as Debian or Fedora this may not be the version
that your distro offers. In those cases please file a bug against the distro
package, not against upstream vdirsyncer.
* Use ``--verbosity=DEBUG`` when including output from vdirsyncer.
Suggesting features
-------------------
If you're suggesting a feature, keep in mind that vdirsyncer tries not to be a
full calendar or contacts client, but rather just the piece of software that
synchronizes all the data. :doc:`Take a look at the documentation for software
working with vdirsyncer <tutorials/index>`.
Submitting patches, pull requests
=================================
* **Discuss everything in the issue tracker first** (or contact me somehow
else) before implementing it.
* Make sure the tests pass. See below for running them.
* But not because you wrote too few tests.
* Add yourself to ``AUTHORS.rst``, and add a note to ``CHANGELOG.rst`` too.
Running tests, how to set up your development environment
---------------------------------------------------------
For many patches, it might suffice to just let CI run the tests. However,
CI is slow, so you might want to run them locally too. For this, set up a
virtualenv_ and run this inside of it::
# Install development dependencies, including:
# - vdirsyncer from the repo into the virtualenv
# - style checks and formatting (ruff)
make install-dev
# Install git commit hook for some extra linting and checking
pre-commit install
Then you can run::
pytest # The normal testsuite
pre-commit run --all # Run all linters (which also run via pre-commit)
make -C docs html # Build the HTML docs, output is at docs/_build/html/
make -C docs linkcheck # Check docs for any broken links
The ``Makefile`` has a lot of options that allow you to control which tests are
run, and which servers are tested. Take a look at its code where they are all
initialized and documented.
To tests against a specific DAV server, use ``DAV_SERVER``::
make DAV_SERVER=xandikos test
The server will be initialised in a docker container and terminated at the end
of the test suite.
If you have any questions, feel free to open issues about it.
Structure of the testsuite
--------------------------
Within ``tests/``, there are three main folders:
- ``system`` contains system- and also integration tests. A rough rule is: If
the test is using temporary files, put it here.
- ``unit``, where each testcase tests a single class or function.
- ``storage`` runs a generic storage testsuite against all storages.
The reason for this separation is: We are planning to generate separate
coverage reports for each of those testsuites. Ideally ``unit`` would generate
palatable coverage of the entire codebase *on its own*, and the *combination*
of ``system`` and ``storage`` as well.
.. _virtualenv: http://virtualenv.readthedocs.io/

15
docs/donations.rst Normal file
View file

@ -0,0 +1,15 @@
=========
Donations
=========
vdirsyncer is and will always be free and open source software. We appreciate
sponsors willing to fund our continued work on it.
If you found my work useful, please consider donating. Thank you!
- Bitcoin: ``13p42uWDL62bNRH3KWA6cSpSgvnHy1fs2E``.
- Sponsor via one-time tips or recurring donations `via Ko-fi`_.
- Sponsor via recurring donations `via liberapay`_.
.. _via Ko-fi: https://ko-fi.com/whynothugo
.. _via liberapay: https://liberapay.com/WhyNotHugo/

View file

@ -2,24 +2,49 @@
vdirsyncer vdirsyncer
========== ==========
vdirsyncer synchronizes your calendars and addressbooks between two storages. - `Documentation <https://vdirsyncer.pimutils.org/en/stable/>`_
The supported storages are CalDAV, CardDAV, arbitrary HTTP resources, `vdir - `Source code <https://github.com/pimutils/vdirsyncer>`_
<https://github.com/untitaker/vdir>`_ and :ref:`some more <storages>`.
It aims to be for CalDAV and CardDAV what `OfflineIMAP Vdirsyncer is a command-line tool for synchronizing calendars and addressbooks
<http://offlineimap.org/>`_ is for IMAP. between a variety of servers and the local filesystem. The most popular usecase
is to synchronize a server with a local folder and use a set of other
:doc:`programs <tutorials/index>` to change the local events and contacts.
Vdirsyncer can then synchronize those changes back to the server.
Table of Contents However, vdirsyncer is not limited to synchronizing between clients and
================= servers. It can also be used to synchronize calendars and/or addressbooks
between two servers directly.
It aims to be for calendars and contacts what `OfflineIMAP
<http://offlineimap.org/>`_ is for emails.
.. toctree:: .. toctree::
:caption: Users
:maxdepth: 1 :maxdepth: 1
when
installation
tutorial tutorial
api ssl-tutorial
keyring keyring
server_support partial-sync
troubleshooting config
changelog tutorials/index
problems
.. toctree::
:caption: Developers
:maxdepth: 1
contributing
vdir vdir
.. toctree::
:caption: General
:maxdepth: 1
packaging
contact
changelog
license license
donations

122
docs/installation.rst Normal file
View file

@ -0,0 +1,122 @@
.. _installation:
============
Installation
============
OS/distro packages
------------------
The following packages are community-contributed and were up-to-date at the
time of writing:
- `Arch Linux <https://archlinux.org/packages/extra/any/vdirsyncer/>`_
- `Ubuntu and Debian, x86_64-only
<https://packagecloud.io/pimutils/vdirsyncer>`_ (packages also exist
in the official repositories but may be out of date)
- `GNU Guix <https://packages.guix.gnu.org/packages/vdirsyncer/>`_
- `macOS (homebrew) <https://formulae.brew.sh/formula/vdirsyncer>`_
- `NetBSD <https://ftp.netbsd.org/pub/pkgsrc/current/pkgsrc/time/py-vdirsyncer/index.html>`_
- `OpenBSD <http://ports.su/productivity/vdirsyncer>`_
- `Slackware (SlackBuild at Slackbuilds.org) <https://slackbuilds.org/repository/15.0/network/vdirsyncer/>`_
We only support the latest version of vdirsyncer, which is at the time of this
writing |vdirsyncer_version|. Please **do not file bugs if you use an older
version**.
Some distributions have multiple release channels. Debian and Fedora for
example have a "stable" release channel that ships an older version of
vdirsyncer. Those versions aren't supported either.
If there is no suitable package for your distribution, you'll need to
:ref:`install vdirsyncer manually <manual-installation>`. There is an easy
command to copy-and-paste for this as well, but you should be aware of its
consequences.
.. _manual-installation:
Manual installation
-------------------
If your distribution doesn't provide a package for vdirsyncer, you still can
use Python's package manager "pip". First, you'll have to check that the
following things are installed:
- Python 3.9 to 3.13 and pip.
- ``libxml`` and ``libxslt``
- ``zlib``
- Linux or macOS. **Windows is not supported**, see :gh:`535`.
On Linux systems, using the distro's package manager is the best
way to do this, for example, using Ubuntu::
sudo apt-get install libxml2 libxslt1.1 zlib1g python3
Then you have several options. The following text applies for most Python
software by the way.
pipx: The clean, easy way
~~~~~~~~~~~~~~~~~~~~~~~~~
pipx_ is a new package manager for Python-based software that automatically
sets up a virtual environment for each program it installs. Please note that
installing via pipx will not include manual pages nor systemd services.
pipx will install vdirsyncer into ``~/.local/pipx/venvs/vdirsyncer``
Assuming that pipx is installed, vdirsyncer can be installed with::
pipx install vdirsyncer
It can later be updated to the latest version with::
pipx upgrade vdirsyncer
And can be uninstalled with::
pipx uninstall vdirsyncer
This last command will remove vdirsyncer and any dependencies installed into
the above location.
.. _pipx: https://github.com/pipxproject/pipx
The dirty, easy way
~~~~~~~~~~~~~~~~~~~
If pipx is not available on your distribution, the easiest way to install
vdirsyncer at this point would be to run::
pip install --ignore-installed vdirsyncer
- ``--ignore-installed`` is to work around Debian's potentially broken packages
(see :ref:`debian-urllib3`).
This method has a major flaw though: Pip doesn't keep track of the files it
installs. Vdirsyncer's files would be located somewhere in
``~/.local/lib/python*``, but you can't possibly know which packages were
installed as dependencies of vdirsyncer and which ones were not, should you
decide to uninstall it. In other words, using pip that way would pollute your
home directory.
The clean, hard way
~~~~~~~~~~~~~~~~~~~
There is a way to install Python software without scattering stuff across
your filesystem: virtualenv_. There are a lot of resources on how to use it,
the simplest possible way would look something like::
virtualenv ~/vdirsyncer_env
~/vdirsyncer_env/bin/pip install vdirsyncer
alias vdirsyncer="~/vdirsyncer_env/bin/vdirsyncer"
You'll have to put the last line into your ``.bashrc`` or ``.bash_profile``.
This method has two advantages:
- It separately installs all Python packages into ``~/vdirsyncer_env/``,
without relying on the system packages. This works around OS- or
distro-specific issues.
- You can delete ``~/vdirsyncer_env/`` to uninstall vdirsyncer entirely.
.. _virtualenv: https://virtualenv.readthedocs.io/

View file

@ -1,55 +1,96 @@
=============== =================
Keyring Support Storing passwords
=================
.. versionchanged:: 0.7.0
Password configuration got completely overhauled.
Vdirsyncer can fetch passwords from several sources other than the config file.
Command
=======
Say you have the following configuration::
[storage foo]
type = "caldav"
url = ...
username = "foo"
password = "bar"
But it bugs you that the password is stored in cleartext in the config file.
You can do this::
[storage foo]
type = "caldav"
url = ...
username = "foo"
password.fetch = ["command", "~/get-password.sh", "more", "args"]
You can fetch the username as well::
[storage foo]
type = "caldav"
url = ...
username.fetch = ["command", "~/get-username.sh"]
password.fetch = ["command", "~/get-password.sh"]
Or really any kind of parameter in a storage section.
You can also pass the command as a string to be executed in a shell::
[storage foo]
...
password.fetch = ["shell", "~/.local/bin/get-my-password | head -n1"]
With pass_ for example, you might find yourself writing something like this in
your configuration file::
password.fetch = ["command", "pass", "caldav"]
.. _pass: https://www.passwordstore.org/
Accessing the system keyring
----------------------------
As shown above, you can use the ``command`` strategy to fetch your credentials
from arbitrary sources. A very common usecase is to fetch your password from
the system keyring.
The keyring_ Python package contains a command-line utility for fetching
passwords from the OS's password store. Installation::
pip install keyring
Basic usage::
password.fetch = ["command", "keyring", "get", "example.com", "foouser"]
.. _keyring: https://github.com/jaraco/keyring/
Password Prompt
=============== ===============
*vdirsyncer* will try the following storages if no password (but a username) is You can also simply prompt for the password::
set in your config. If that fails too, it will prompt for the password and
store the password in the system keyring (if possible and wished).
netrc [storage foo]
===== type = "caldav"
username = "myusername"
password.fetch = ["prompt", "Password for CalDAV"]
*vdirsyncer* can use ``~/.netrc`` for retrieving a password. An example Environment variable
``.netrc`` looks like this:: ===============
machine owncloud.example.com To read the password from an environment variable::
login foouser
password foopass
System Keyring [storage foo]
============== type = "caldav"
username = "myusername"
password.fetch = ["command", "printenv", "DAV_PW"]
*vdirsyncer* can also use your system's password storage for saving password in This is especially handy if you use the same password multiple times
a (more) secure way. (say, for a CardDAV and a CalDAV storage).
On bash, you can read and export the password without printing::
To use it, you must install keyring_. read -s DAV_PW "DAV Password: " && export DAV_PW
.. _keyring: https://bitbucket.org/kang/python-keyring-lib
*vdirsyncer* will use the full resource URL as the key when saving.
When retrieving the key, it will try to remove segments of the URL's path until
it finds a password. For example, if you save a password under the key
``vdirsyncer:http://example.com``, it will be used as a fallback for all
resources on ``example.com``. If you additionally save a password under the key
``vdirsyncer:http://example.com/special/``, that password will be used for all
resources on ``example.com`` whose path starts with ``/special/``.
*keyring* support these keyrings:
- **OSXKeychain:** The Keychain service in Mac OS X.
- **KDEKWallet:** The KDE's Kwallet service.
- **GnomeKeyring** For Gnome 2 environment.
- **SecretServiceKeyring:** For newer GNOME and KDE environments.
- **WinVaultKeyring:** The Windows Credential Vault
- **Win32CryptoKeyring:** for Windows 2k+.
- **CryptedFileKeyring:** A command line interface keyring base on PyCrypto.
- **UncryptedFileKeyring:** A keyring which leaves passwords directly in file.
Changing the Password
---------------------
If your password on the server changed or you misspelled it you need to use
your system's password manager (e.g. seahorse for most Linux distrubutions) to
either delete or directly change it, *vdirsyncer* currently has no means to do
it for you.

View file

@ -2,7 +2,7 @@
Credits and License Credits and License
=================== ===================
.. include:: ../CONTRIBUTORS.rst .. include:: ../AUTHORS.rst
License License
======= =======

92
docs/packaging.rst Normal file
View file

@ -0,0 +1,92 @@
====================
Packaging guidelines
====================
Thank you very much for packaging vdirsyncer! The following guidelines should
help you to avoid some common pitfalls.
If you find yourself needing to patch anything, or going in a different direction,
please open an issue so we can also address in a way that works for everyone. Otherwise
we get bug reports for code or scenarios that don't exist in upstream vdirsycner.
Obtaining the source code
=========================
The main distribution channel is `PyPI
<https://pypi.python.org/pypi/vdirsyncer>`_, and source tarballs can be
obtained there. We mirror the same package tarball and wheel as GitHub
releases. Please do not confuse these with the auto-generated GitHub "Source
Code" tarball. Those are missing some important metadata and your build will fail.
We give each release a tag in the git repo. If you want to get notified of new
releases, `GitHub's feed
<https://github.com/pimutils/vdirsyncer/releases.atom>`_ is a good way.
Tags will be signed by the maintainer who is doing the release (starting with
0.16.8), and generation of the tarball and wheel is done by CI. Hence, only the
tag itself is signed.
Dependency versions
===================
As with most Python packages, ``setup.py`` denotes the dependencies of
vdirsyncer. It also contains lower-bound versions of each dependency. Older
versions will be rejected by the testsuite.
Testing
=======
Everything testing-related goes through the ``Makefile`` in the root of the
repository or PyPI package. Trying to e.g. run ``pytest`` directly will
require a lot of environment variables to be set (for configuration) and you
probably don't want to deal with that.
You can install the all development dependencies with::
make install-dev
You probably don't want this since it will use pip to download the
dependencies. Alternatively test dependencies are listed as ``test`` optional
dependencies in ``pyproject.toml``, again with lower-bound version
requirements.
You also have to have vdirsyncer fully installed at this point. Merely
``cd``-ing into the tarball will not be sufficient.
Running the tests happens with::
pytest
Hypothesis will randomly generate test input. If you care about deterministic
tests, set the ``DETERMINISTIC_TESTS`` variable to ``"true"``::
make DETERMINISTIC_TESTS=true test
There are a lot of additional variables that allow you to test vdirsyncer
against a particular server. Those variables are not "stable" and may change
drastically between minor versions. Just don't use them, you are unlikely to
find bugs that vdirsyncer's CI hasn't found.
Documentation
=============
Using Sphinx_ you can generate the documentation you're reading right now in a
variety of formats, such as HTML, PDF, or even as a manpage. That said, I only
take care of the HTML docs' formatting.
You can find a list of dependencies in ``pyproject.toml``, in the
``project.optional-dependencies`` section as ``docs``. Again, you can install
those using pip with::
pip install '.[docs]'
Then change into the ``docs/`` directory and build whatever format you want
using the ``Makefile`` in there (run ``make`` for the formats you can build).
.. _Sphinx: www.sphinx-doc.org/
Contrib files
=============
Reference ``systemd.service`` and ``systemd.timer`` unit files are provided. It
is recommended to install this if your distribution is systemd-based.

72
docs/partial-sync.rst Normal file
View file

@ -0,0 +1,72 @@
.. _partial_sync_tutorial:
===============================
Syncing with read-only storages
===============================
If you want to subscribe to a public, read-only `WebCAL
<https://en.wikipedia.org/wiki/Webcal>`_-calendar but neither your server nor
your calendar apps support that (or support it insufficiently), vdirsyncer can
be used to synchronize such a public calendar ``A`` with a new calendar ``B``
of your own and keep ``B`` updated.
Step 1: Create the target calendar
==================================
First you need to create the calendar you want to sync the WebCAL-calendar
with. Most servers offer a web interface for this. You then need to note the
CalDAV URL of your calendar. Note that this URL should directly point to the
calendar you just created, which means you would have one such URL for each
calendar you have.
Step 2: Creating the config
===========================
Paste this into your vdirsyncer config::
[pair holidays]
a = "holidays_public"
b = "holidays_private"
collections = null
[storage holidays_public]
type = "http"
# The URL to your iCalendar file.
url = "..."
[storage holidays_private]
type = "caldav"
# The direct URL to your calendar.
url = "..."
# The credentials to your CalDAV server
username = "..."
password = "..."
Then run ``vdirsyncer discover holidays`` and ``vdirsyncer sync holidays``, and
your previously created calendar should be filled with events.
Step 3: The partial_sync parameter
==================================
.. versionadded:: 0.14
You may get into a situation where you want to hide or modify some events from
your ``holidays`` calendar. If you try to do that at this point, you'll notice
that vdirsyncer will revert any changes you've made after a few times of
running ``sync``. This is because vdirsyncer wants to keep everything in sync,
and it can't synchronize changes to the public holidays-calendar because it
doesn't have the rights to do so.
For such purposes you can set the ``partial_sync`` parameter to ``ignore``::
[pair holidays]
a = "holidays_public"
b = "holidays_private"
collections = null
partial_sync = ignore
See :ref:`the config docs <partial_sync_def>` for more information.
.. _nextCloud: https://nextcloud.com/
.. _Baikal: http://sabre.io/baikal/
.. _DAViCal: http://www.davical.org/

22
docs/problems.rst Normal file
View file

@ -0,0 +1,22 @@
==============
Known Problems
==============
For any unanswered questions or problems, see :doc:`contact`.
.. _debian-urllib3:
Requests-related ImportErrors
-----------------------------
ImportError: No module named packages.urllib3.poolmanager
ImportError: cannot import name iter_field_objects
Debian and nowadays even other distros make modifications to the ``requests``
package that don't play well with packages assuming a normal ``requests``. This
is due to stubbornness on both sides.
See :gh:`82` and :gh:`140` for past discussions. You have one option to work
around this, that is, to install vdirsyncer in a virtual environment, see
:ref:`manual-installation`.

View file

@ -1,49 +0,0 @@
==============
Server Support
==============
vdirsyncer is currently regularly and automatically tested against the latest
versions of Radicale and ownCloud. In principle, vdirsyncer is supposed to run
correctly with any remotely popular CalDAV or CardDAV server.
vdirsyncer's synchronization works best if the items have ``UID`` properties.
Items which don't have this property still should be synchronized fine as of
version 1.5, but for performance reasons, such items should rather be the
exception than the rule. For a possible way to automatically fix such items,
take a look at `vfix <https://github.com/geier/vfix>`_.
Radicale
========
Vdirsyncer is tested against the git version and the latest PyPI release of
Radicale.
- Radicale doesn't `support time ranges in the calendar-query of CalDAV
<https://github.com/Kozea/Radicale/issues/146>`_, so setting ``start_date``
and ``end_date`` for :py:class:`vdirsyncer.storage.CaldavStorage` will have
no or unpredicted consequences.
- `Versions of Radicale older than 0.9b1 choke on RFC-conform queries for all
items of a collection <https://github.com/Kozea/Radicale/issues/143>`_.
Vdirsyncer's default value ``'VTODO, VEVENT'`` for
:py:class:`vdirsyncer.storage.CaldavStorage`'s ``item_types`` parameter will
work fine with these versions, and so will all values, except for the empty
one.
The empty value ``''`` will get vdirsyncer to send a single HTTP request to
fetch all items, instead of one HTTP request for each possible item type. As
the linked issue describes, old versions of Radicale expect a
non-RFC-compliant format for such queries, one which vdirsyncer doesn't
support.
ownCloud
========
Vdirsyncer is tested against the latest version of ownCloud.
- *Versions older than 7.0.0:* ownCloud uses SabreDAV, which had problems
detecting collisions and race-conditions. The problems were reported and are
fixed in SabreDAV's repo, and the corresponding fix is also in ownCloud since
7.0.0. See `Bug #16 <https://github.com/untitaker/vdirsyncer/issues/16>`_ for
more information.

72
docs/ssl-tutorial.rst Normal file
View file

@ -0,0 +1,72 @@
.. _ssl-tutorial:
==============================
SSL and certificate validation
==============================
All SSL configuration is done per-storage.
Pinning by fingerprint
----------------------
To pin the certificate by fingerprint::
[storage foo]
type = "caldav"
...
verify_fingerprint = "6D:83:EA:32:6C:39:BA:08:ED:EB:C9:BC:BE:12:BB:BF:0F:D9:83:00:CC:89:7E:C7:32:05:94:96:CA:C5:59:5E"
SHA256-Fingerprints must be used, MD5 and SHA-1 are insecure and not supported.
CA validation is disabled when pinning a fingerprint.
You can use the following command for obtaining a SHA256 fingerprint::
echo -n | openssl s_client -connect unterwaditzer.net:443 | openssl x509 -noout -fingerprint -sha256
However, please consider using `Let's Encrypt <https://letsencrypt.org/>`_ such
that you can forget about all of that. It is easier to deploy a free
certificate from them than configuring all of your clients to accept the
self-signed certificate.
.. _ssl-cas:
Custom root CAs
---------------
To point vdirsyncer to a custom set of root CAs::
[storage foo]
type = "caldav"
...
verify = "/path/to/cert.pem"
Vdirsyncer uses the aiohttp_ library, which uses the default `ssl.SSLContext
https://docs.python.org/3/library/ssl.html#ssl.SSLContext`_ by default.
There are cases where certificate validation fails even though you can access
the server fine through e.g. your browser. This usually indicates that your
installation of ``python`` or the ``aiohttp`` or library is somehow broken. In
such cases, it makes sense to explicitly set ``verify`` or
``verify_fingerprint`` as shown above.
.. _aiohttp: https://docs.aiohttp.org/en/stable/index.html
.. _ssl-client-certs:
Client Certificates
-------------------
Client certificates may be specified with the ``auth_cert`` parameter. If the
key and certificate are stored in the same file, it may be a string::
[storage foo]
type = "caldav"
...
auth_cert = "/path/to/certificate.pem"
If the key and certificate are separate, a list may be used::
[storage foo]
type = "caldav"
...
auth_cert = ["/path/to/certificate.crt", "/path/to/key.key"]

View file

@ -1,16 +0,0 @@
===============
Troubleshooting
===============
- **[Errno 185090050] _ssl.c:343: error:0B084002:x509 certificate
routines:X509_load_cert_crl_file:system lib**
vdirsyncer cannot find the path to your certificate bundle, you need to
supply it as a parameter to ``verify`` in your config file, e.g.::
verify = /usr/share/ca-certificates/cacert.org/cacert.org_root.crt
- **During sync an error occurs: TypeError: request() got an unexpected keyword
argument 'verify'**
You need to update your version of requests.

View file

@ -2,33 +2,47 @@
Tutorial Tutorial
======== ========
Before starting, :doc:`consider if you actually need vdirsyncer <when>`. There
are better alternatives available for particular usecases.
Installation Installation
============ ============
- Make sure you have Python 2.7+ or Python 3.3+ installed. See :ref:`installation`.
- ``pip install --user vdirsyncer``
- Check if the ``vdirsyncer`` command is available.
Configuration Configuration
============= =============
.. note:: .. note::
The `example.cfg from the repository
<https://github.com/untitaker/vdirsyncer/blob/master/example.cfg>`_
contains a very terse version of this.
By default, *vdirsyncer* looks for its configuration file at - The `config.example from the repository
``~/.vdirsyncer/config``. You can use the ``VDIRSYNCER_CONFIG`` environment <https://github.com/pimutils/vdirsyncer/blob/main/config.example>`_
variable to change this path. contains a very terse version of this.
- In this example we set up contacts synchronization, but calendar sync
works almost the same. Just swap ``type = "carddav"``
for ``type = "caldav"`` and ``fileext = ".vcf"``
for ``fileext = ".ics"``.
- Take a look at the :doc:`problems` page if anything doesn't work like
planned.
By default, vdirsyncer looks for its configuration file in the following
locations:
- The file pointed to by the ``VDIRSYNCER_CONFIG`` environment variable.
- ``~/.vdirsyncer/config``.
- ``$XDG_CONFIG_HOME/vdirsyncer/config``, which is normally
``~/.config/vdirsyncer/config``. See the XDG-Basedir_ specification.
.. _XDG-Basedir: http://standards.freedesktop.org/basedir-spec/basedir-spec-latest.html#variables
The config file should start with a :ref:`general section <general_config>`, The config file should start with a :ref:`general section <general_config>`,
where the only required parameter is ``status_path``. The following is a where the only required parameter is ``status_path``. The following is a
minimal example:: minimal example::
[general] [general]
status_path = ~/.vdirsyncer/status/ status_path = "~/.vdirsyncer/status/"
After the general section, an arbitrary amount of *pair and storage sections* After the general section, an arbitrary amount of *pair and storage sections*
might come. might come.
@ -36,71 +50,236 @@ might come.
In vdirsyncer, synchronization is always done between two storages. Such In vdirsyncer, synchronization is always done between two storages. Such
storages are defined in :ref:`storage sections <storage_config>`, and which storages are defined in :ref:`storage sections <storage_config>`, and which
pairs of storages should actually be synchronized is defined in :ref:`pair pairs of storages should actually be synchronized is defined in :ref:`pair
section <pair_config>`. section <pair_config>`. This format is copied from OfflineIMAP, where storages
are called repositories and pairs are called accounts.
This format is copied from OfflineIMAP, where storages are called The following example synchronizes ownCloud's addressbooks to ``~/.contacts/``::
repositories and pairs are called accounts.
The following example synchronizes a single CardDAV-addressbook to
``~/.contacts/``::
[pair my_contacts] [pair my_contacts]
a = my_contacts_local a = "my_contacts_local"
b = my_contacts_remote b = "my_contacts_remote"
collections = ["from a", "from b"]
[storage my_contacts_local] [storage my_contacts_local]
type = filesystem type = "filesystem"
path = ~/.contacts/ path = "~/.contacts/"
fileext = .vcf fileext = ".vcf"
[storage my_contacts_remote] [storage my_contacts_remote]
type = carddav type = "carddav"
url = https://owncloud.example.com/remote.php/carddav/addressbooks/bob/default/
username = bob
password = asdf
After running ``vdirsyncer sync``, ``~/.contacts/`` will contain a bunch of # We can simplify this URL here as well. In theory it shouldn't matter.
``.vcf`` files which all contain a contact in ``VCARD`` format each. You can url = "https://owncloud.example.com/remote.php/carddav/"
modify their content, add new ones and delete some, and your changes will be username = "bob"
synchronized to the CalDAV server after you run ``vdirsyncer sync`` again. For password = "asdf"
further reference, it uses the storages
:py:class:`vdirsyncer.storage.FilesystemStorage` and
:py:class:`vdirsyncer.storage.CarddavStorage`.
But what if we want to synchronize multiple addressbooks from the same server? .. note::
Of course we could create new pairs and storages for each addressbook, but that
is very tedious to do. Instead we will use a shortcut:
- Remove the last segment from the URL, so that it ends with ``.../bob/`` Configuration for other servers can be found at :ref:`supported-servers`.
instead of ``.../bob/default/``.
- Add the following line to the *pair* section:: After running ``vdirsyncer discover`` and ``vdirsyncer sync``, ``~/.contacts/``
will contain subfolders for each addressbook, which in turn will contain a
bunch of ``.vcf`` files which all contain a contact in ``VCARD`` format each.
You can modify their contents, add new ones and delete some [1]_, and your
changes will be synchronized to the CalDAV server after you run ``vdirsyncer
sync`` again. For further reference, it uses the storages :storage:`filesystem`
and :storage:`carddav`.
[pair my_contacts] However, if new collections are created on the server, it will not
... automatically start synchronizing those [2]_. You need to run ``vdirsyncer
collections = default,work discover`` again to re-fetch this list instead.
This will synchronize .. [1] You'll want to :doc:`use a helper program for this <tutorials/index>`.
``https://owncloud.example.com/remote.php/carddav/addressbooks/bob/default/``
with ``~/.contacts/default/`` and
``https://owncloud.example.com/remote.php/carddav/addressbooks/bob/work/`` with
``~/.contacts/work/``. Under the hood, vdirsyncer also just copies the pairs
and storages for each collection and appends the collection name to the path or
URL.
It almost seems like it could work. But what if the same item is changed on .. [2] Because collections are added rarely, and checking for this case before
both sides? What should vdirsyncer do? By default, it will show an ugly error every synchronization isn't worth the overhead.
message, which is surely a way to avoid the problem. Another way to solve that
ambiguity is to add another line to the *pair* section:: More Configuration
==================
.. _conflict_resolution_tutorial:
Conflict resolution
-------------------
What if the same item is changed on both sides? What should vdirsyncer
do? Three options are currently provided:
1. vdirsyncer displays an error message (the default);
2. vdirsyncer chooses one alternative version over the other;
3. vdirsyncer starts a command of your choice that is supposed to merge the two alternative versions.
Options 2 and 3 require adding a ``"conflict_resolution"``
parameter to the pair section. Option 2 requires giving either ``"a
wins"`` or ``"b wins"`` as value to the parameter::
[pair my_contacts] [pair my_contacts]
... ...
conflict_resolution = b wins conflict_resolution = "b wins"
Earlier we wrote that ``b = my_contacts_remote``, so when vdirsyncer encounters Earlier we wrote that ``b = "my_contacts_remote"``, so when vdirsyncer encounters
the situation where an item changed on both sides, it will simply overwrite the the situation where an item changed on both sides, it will simply overwrite the
local item with the one from the server. Of course ``a wins`` is also a valid local item with the one from the server.
value.
Calendar sync works almost the same. Just swap ``type = carddav`` for ``type = Option 3 requires specifying as value of ``"conflict_resolution"`` an
caldav`` and ``fileext = .vcf`` for ``fileext = .ics``. array starting with ``"command"`` and containing paths and arguments
to a command. For example::
[pair my_contacts]
...
conflict_resolution = ["command", "vimdiff"]
In this example, ``vimdiff <a> <b>`` will be called with ``<a>`` and
``<b>`` being two temporary files containing the conflicting
files. The files need to be exactly the same when the command
returns. More arguments can be passed to the command by adding more
elements to the array.
See :ref:`pair_config` for the reference documentation.
.. _metasync_tutorial:
Metadata synchronization
------------------------
Besides items, vdirsyncer can also synchronize metadata like the addressbook's
or calendar's "human-friendly" name (internally called "displayname") or the
color associated with a calendar. For the purpose of explaining this feature,
let's switch to a different base example. This time we'll synchronize calendars::
[pair my_calendars]
a = "my_calendars_local"
b = "my_calendars_remote"
collections = ["from a", "from b"]
metadata = ["color"]
[storage my_calendars_local]
type = "filesystem"
path = "~/.calendars/"
fileext = ".ics"
[storage my_calendars_remote]
type = "caldav"
url = "https://owncloud.example.com/remote.php/caldav/"
username = "bob"
password = "asdf"
Run ``vdirsyncer discover`` for discovery. Then you can use ``vdirsyncer
metasync`` to synchronize the ``color`` property between your local calendars
in ``~/.calendars/`` and your ownCloud. Locally the color is just represented
as a file called ``color`` within the calendar folder.
.. _collections_tutorial:
More information about collections
----------------------------------
"Collection" is a collective term for addressbooks and calendars. A Cardav or
Caldav server can contains several "collections" which correspond to several
addressbooks or calendar.
Each collection from a storage has a "collection name", a unique identifier for each
collection. In the case of :storage:`filesystem`-storage, this is the name of the
directory that represents the collection, in the case of the DAV-storages this
is the last segment of the URL. We use this identifier in the ``collections``
parameter in the ``pair``-section.
This identifier doesn't change even if you rename your calendar in whatever UI
you have, because that only changes the so-called "displayname" property [3]_.
On some servers (iCloud, Google) this identifier is randomly generated and has
no correlation with the displayname you chose.
.. [3] Which you can also synchronize with ``metasync`` using ``metadata =
["displayname"]``.
There are three collection names that have a special meaning:
- ``"from a"``, ``"from b"``: A placeholder for all collections that can be
found on side A/B when running ``vdirsyncer discover``.
- ``null``: The parameters give to the storage are exact and require no discovery.
The last one requires a bit more explanation. Assume this config which
synchronizes two directories of addressbooks::
[pair foobar]
a = "foo"
b = "bar"
collections = ["from a", "from b"]
[storage foo]
type = "filesystem"
fileext = ".vcf"
path = "./contacts_foo/"
[storage bar]
type = "filesystem"
fileext = ".vcf"
path = "./contacts_bar/"
As we saw previously this will synchronize all collections in
``./contacts_foo/`` with each same-named collection in ``./contacts_bar/``. If
there's a collection that exists on one side but not the other, vdirsyncer will
ask whether to create that folder on the other side.
If we set ``collections = null``, ``./contacts_foo/`` and ``./contacts_bar/``
are no longer treated as folders with collections, but as collections
themselves. This means that ``./contacts_foo/`` and ``./contacts_bar/`` will
contain ``.vcf``-files, not subfolders that contain ``.vcf``-files.
This is useful in situations where listing all collections fails because your
DAV-server doesn't support it, for example. In this case, you can set ``url``
of your :storage:`carddav`- or :storage:`caldav`-storage to a URL that points
to your CalDAV/CardDAV collection directly.
Note that not all storages support the ``null``-collection, for example
:storage:`google_contacts` and :storage:`google_calendar` don't.
Advanced collection configuration (server-to-server sync)
---------------------------------------------------------
The examples above are good enough if you want to synchronize a remote server
to a previously empty disk. However, even more trickery is required when you
have two servers with *already existing* collections which you want to
synchronize.
The core problem in this situation is that vdirsyncer pairs collections by
collection name by default (see definition in previous section, basically a
foldername or a remote UUID). When you have two servers, those collection names
may not line up as nicely. Suppose you created two calendars "Test", one on a
NextCloud server and one on iCloud, using their respective web interfaces. The
URLs look something like this::
NextCloud: https://example.com/remote.php/dav/calendars/user/test/
iCloud: https://p-XX.caldav.icloud.com/YYY/calendars/3b4c9995-5c67-4021-9fa0-be4633623e1c
Those are two DAV calendar collections. Their collection names will be ``test``
and ``3b4c9995-5c67-4021-9fa0-be4633623e1c`` respectively, so you don't have a
single name you can address them both with. You will need to manually "pair"
(no pun intended) those collections up like this::
[pair doublecloud]
a = "my_nextcloud"
b = "my_icloud"
collections = [["mytest", "test", "3b4c9995-5c67-4021-9fa0-be4633623e1c"]]
``mytest`` gives that combination of calendars a nice name you can use when
talking about it, so you would use ``vdirsyncer sync doublecloud/mytest`` to
say: "Only synchronize these two storages, nothing else that may be
configured".
.. note:: Why not use displaynames?
You may wonder why vdirsyncer just couldn't figure this out by itself. After
all, you did name both collections "Test" (which is called "the
displayname"), so why not pair collections by that value?
There are a few problems with this idea:
- Two calendars may have the same exact displayname.
- A calendar may not have a (non-empty) displayname.
- The displayname might change. Either you rename the calendar, or the
calendar renames itself because you change a language setting.
In the end, that property was never designed to be parsed by machines.

10
docs/tutorials/baikal.rst Normal file
View file

@ -0,0 +1,10 @@
======
Baikal
======
Vdirsyncer is continuously tested against the latest version of Baikal_.
- Baikal up to ``0.2.7`` also uses an old version of SabreDAV, with the same
issue as ownCloud, see :gh:`160`. This issue is fixed in later versions.
.. _Baikal: http://sabre.io/baikal/

View file

@ -0,0 +1,95 @@
.. _claws-mail-tutorial:
Vdirsyncer with Claws Mail
==========================
First of all, Claws-Mail only supports **read-only** functions for vCards. It
can only read contacts, but there's no editor.
Preparation
-----------
We need to install vdirsyncer, for that look :doc:`here </installation>`. Then
we need to create some folders::
mkdir ~/.vdirsyncer
mkdir ~/.contacts
Configuration
-------------
Now we create the configuration for vdirsyncer. Open
``~/.vdirsyncer/config`` with a text editor. The config should look like
this:
.. code:: ini
[general]
status_path = "~/.vdirsyncer/status/"
[storage local]
type = "singlefile"
path = "~/.contacts/%s.vcf"
[storage online]
type = "carddav"
url = "CARDDAV_LINK"
username = "USERNAME"
password = "PASSWORD"
read_only = true
[pair contacts]
a = "local"
b = "online"
collections = ["from a", "from b"]
conflict_resolution = "b wins"
- In the general section, we define the status folder path, for discovered
collections and generally stuff that needs to persist between syncs.
- In the local section we define that all contacts should be sync in a single
file and the path for the contacts.
- In the online section you must change the url, username and password to your
setup. We also set the storage to read-only such that no changes get
synchronized back. Claws-Mail should not be able to do any changes anyway,
but this is one extra safety step in case files get corrupted or vdirsyncer
behaves erratically. You can leave that part out if you want to be able to
edit those files locally.
- In the last section we configure that online contacts win in a conflict
situation. Configure this part however you like. A correct value depends on
which side is most likely to be up-to-date.
Sync
----
Now we discover and sync our contacts::
vdirsyncer discover contacts
vdirsyncer sync contacts
Claws Mail
----------
Open Claws-Mail. Go to **Tools** => **Addressbook**.
Click on **Addressbook** => **New vCard**. Choose a name for the book.
Then search for the for the vCard in the folder **~/.contacts/**. Click
ok, and you we will see your contacts.
.. note::
Claws-Mail shows only contacts that have a mail address.
Crontab
-------
On the end we create a crontab, so that vdirsyncer syncs automatically
every 30 minutes our contacts::
crontab -e
On the end of that file enter this line::
*/30 * * * * /usr/local/bin/vdirsyncer sync > /dev/null
And you're done!

View file

@ -0,0 +1,41 @@
.. _davmail_setup:
===========================
DavMail (Exchange, Outlook)
===========================
DavMail_ is a proxy program that allows you to use Card- and CalDAV clients
with Outlook. That allows you to use vdirsyncer with Outlook.
In practice your success with DavMail may wildly vary. Depending on your
Exchange server you might get confronted with weird errors of all sorts
(including data-loss).
**Make absolutely sure you use the latest DavMail**::
[storage outlook]
type = "caldav"
url = "http://localhost:1080/users/user@example.com/calendar/"
username = "user@example.com"
password = "..."
- Older versions of DavMail handle URLs case-insensitively. See :gh:`144`.
- DavMail is handling malformed data on the Exchange server very poorly. In
such cases the `Calendar Checking Tool for Outlook
<https://www.microsoft.com/en-us/download/details.aspx?id=28786>`_ might
help.
- In some cases, you may see errors about duplicate events. It may look
something like this::
error: my_calendar/calendar: Storage "my_calendar_remote/calendar" contains multiple items with the same UID or even content. Vdirsyncer will now abort the synchronization of this collection, because the fix for this is not clear; It could be the result of a badly behaving server. You can try running:
error:
error: vdirsyncer repair my_calendar_remote/calendar
error:
error: But make sure to have a backup of your data in some form. The offending hrefs are:
[...]
In order to fix this, you can try the Remove-DuplicateAppointments.ps1_
PowerShell script that Microsoft has come up with in order to remove duplicates.
.. _DavMail: http://davmail.sourceforge.net/
.. _Remove-DuplicateAppointments.ps1: https://blogs.msdn.microsoft.com/emeamsgdev/2015/02/12/powershell-remove-duplicate-calendar-appointments/

View file

@ -0,0 +1,23 @@
========
FastMail
========
Vdirsyncer is continuously tested against FastMail_, thanks to them for
providing a free account for this purpose. There are no known issues with it.
`FastMail's support pages
<https://www.fastmail.com/help/technical/servernamesandports.html>`_ provide
the settings to use::
[storage cal]
type = "caldav"
url = "https://caldav.fastmail.com/"
username = "..."
password = "..."
[storage card]
type = "carddav"
url = "https://carddav.fastmail.com/"
username = "..."
password = "..."
.. _FastMail: https://www.fastmail.com/

View file

@ -0,0 +1,9 @@
======
Google
======
Using vdirsyncer with Google Calendar is possible as of 0.10, but it is not
tested frequently. You can use :storage:`google_contacts` and
:storage:`google_calendar`.
For more information see :gh:`202` and :gh:`8`.

35
docs/tutorials/icloud.rst Normal file
View file

@ -0,0 +1,35 @@
.. _icloud_setup:
======
iCloud
======
Vdirsyncer is regularly tested against iCloud_.
::
[storage cal]
type = "caldav"
url = "https://caldav.icloud.com/"
username = "..."
password = "..."
[storage card]
type = "carddav"
url = "https://contacts.icloud.com/"
username = "..."
password = "..."
Problems:
- Vdirsyncer can't do two-factor auth with iCloud (there doesn't seem to be a
way to do two-factor auth over the DAV APIs) You'll need to use `app-specific
passwords <https://support.apple.com/en-us/HT204397>`_ instead.
- iCloud has a few special requirements when creating collections. In principle
vdirsyncer can do it, but it is recommended to create them from an Apple
client (or the iCloud web interface).
- iCloud requires a minimum length of collection names.
- Calendars created by vdirsyncer cannot be used as tasklists.
.. _iCloud: https://www.icloud.com/

63
docs/tutorials/index.rst Normal file
View file

@ -0,0 +1,63 @@
===============
Other tutorials
===============
The following section contains tutorials not explicitly about any particular
core function of vdirsyncer. They usually show how to integrate vdirsyncer with
third-party software. Because of that, it may be that the information regarding
that other software only applies to specific versions of them.
.. note::
Please :doc:`contribute </contributing>` your own tutorials too! Pages are
often only stubs and are lacking full examples.
Client applications
===================
.. toctree::
:maxdepth: 1
claws-mail
systemd-timer
todoman
Further applications, with missing pages:
- khal_, a CLI calendar application supporting :doc:`vdir </vdir>`. You can use
:storage:`filesystem` with it.
- Many graphical calendar apps such as dayplanner_, Orage_ or rainlendar_ save
a calendar in a single ``.ics`` file. You can use :storage:`singlefile` with
those.
- khard_, a commandline addressbook supporting :doc:`vdir </vdir>`. You can use
:storage:`filesystem` with it.
- contactquery.c_, a small program explicitly written for querying vdirs from
mutt.
- mates_, a commandline addressbook supporting :doc:`vdir </vdir>`.
- vdirel_, access :doc:`vdir </vdir>` contacts from Emacs.
.. _khal: http://lostpackets.de/khal/
.. _dayplanner: http://www.day-planner.org/
.. _Orage: https://gitlab.xfce.org/apps/orage
.. _rainlendar: http://www.rainlendar.net/
.. _khard: https://github.com/scheibler/khard/
.. _contactquery.c: https://github.com/t-8ch/snippets/blob/master/contactquery.c
.. _mates: https://github.com/pimutils/mates.rs
.. _vdirel: https://github.com/DamienCassou/vdirel
.. _supported-servers:
Servers
=======
.. toctree::
:maxdepth: 1
baikal
davmail
fastmail
google
icloud
nextcloud
owncloud
radicale
xandikos

View file

@ -0,0 +1,20 @@
=========
nextCloud
=========
Vdirsyncer is continuously tested against the latest version of nextCloud_::
[storage cal]
type = "caldav"
url = "https://nextcloud.example.com/"
username = "..."
password = "..."
[storage card]
type = "carddav"
url = "https://nextcloud.example.com/"
- WebCAL-subscriptions can't be discovered by vdirsyncer. See `this relevant
issue <https://github.com/nextcloud/calendar/issues/63>`_.
.. _nextCloud: https://nextcloud.com/

View file

@ -0,0 +1,26 @@
.. _owncloud_setup:
========
ownCloud
========
Vdirsyncer is continuously tested against the latest version of ownCloud_::
[storage cal]
type = "caldav"
url = "https://example.com/remote.php/dav/"
username = ...
password = ...
[storage card]
type = "carddav"
url = "https://example.com/remote.php/dav/"
username = ...
password = ...
- *Versions older than 7.0.0:* ownCloud uses SabreDAV, which had problems
detecting collisions and race-conditions. The problems were reported and are
fixed in SabreDAV's repo, and the corresponding fix is also in ownCloud since
7.0.0. See :gh:`16` for more information.
.. _ownCloud: https://owncloud.org/

View file

@ -0,0 +1,26 @@
========
Radicale
========
Radicale_ is a very lightweight server, however, it intentionally doesn't
implement the CalDAV and CardDAV standards completely, which might lead to
issues even with very well-written clients. Apart from its non-conformity with
standards, there are multiple other problems with its code quality and the way
it is maintained. Consider using e.g. :doc:`xandikos` instead.
That said, vdirsyncer is continuously tested against the git version and the
latest PyPI release of Radicale.
- Vdirsyncer can't create collections on Radicale.
- Radicale doesn't `support time ranges in the calendar-query of CalDAV
<https://github.com/Kozea/Radicale/issues/146>`_, so setting ``start_date``
and ``end_date`` for :storage:`caldav` will have no or unpredicted
consequences.
- `Versions of Radicale older than 0.9b1 choke on RFC-conform queries for all
items of a collection <https://github.com/Kozea/Radicale/issues/143>`_.
You have to set ``item_types = ["VTODO", "VEVENT"]`` in
:storage:`caldav` for vdirsyncer to work with those versions.
.. _Radicale: http://radicale.org/

View file

@ -0,0 +1,37 @@
.. _systemd_timer-tutorial:
Running as a systemd.timer
==========================
vdirsyncer includes unit files to run at an interval (by default every 15±5
minutes).
.. note::
These are not installed when installing via pip, only via distribution
packages. If you installed via pip, or your distribution doesn't ship systemd
unit files, you'll need to download vdirsyncer.service_ and vdirsyncer.timer_
into either ``/etc/systemd/user/`` or ``~/.local/share/systemd/user``.
.. _vdirsyncer.service: https://raw.githubusercontent.com/pimutils/vdirsyncer/main/contrib/vdirsyncer.service
.. _vdirsyncer.timer: https://raw.githubusercontent.com/pimutils/vdirsyncer/main/contrib/vdirsyncer.timer
Activation
----------
To activate the timer, just run ``systemctl --user enable vdirsyncer.timer``.
To see logs of previous runs, use ``journalctl --user -u vdirsyncer``.
Configuration
-------------
It's quite possible that the default "every fifteen minutes" interval isn't to
your liking. No default will suit everybody, but this is configurable by simply
running::
systemctl --user edit vdirsyncer.timer
This will open a blank editor, where you can override the timer by including::
OnBootSec=5m # This is how long after boot the first run takes place.
OnUnitActiveSec=15m # This is how often subsequent runs take place.

View file

@ -0,0 +1,69 @@
=======
Todoman
=======
The iCalendar format also supports saving tasks in form of ``VTODO``-entries,
with the same file extension as normal events: ``.ics``. Many CalDAV servers
support synchronizing tasks, vdirsyncer does too.
todoman_ is a CLI task manager supporting :doc:`vdir </vdir>`. Its interface is
similar to the ones of Taskwarrior or the todo.txt CLI app. You can use
:storage:`filesystem` with it.
.. _todoman: http://todoman.readthedocs.io/
Setting up vdirsyncer
=====================
For this tutorial we will use NextCloud.
Assuming a config like this::
[general]
status_path = "~/.vdirsyncer/status/"
[pair calendars]
conflict_resolution = "b wins"
a = "calendars_local"
b = "calendars_dav"
collections = ["from b"]
metadata = ["color", "displayname"]
[storage calendars_local]
type = "filesystem"
path = "~/.calendars/"
fileext = ".ics"
[storage calendars_dav]
type = "caldav"
url = "https://nextcloud.example.net/"
username = "..."
password = "..."
``vdirsyncer sync`` will then synchronize the calendars of your NextCloud_
instance to subfolders of ``~/.calendar/``.
.. _NextCloud: https://nextcloud.com/
Setting up todoman
==================
Write this to ``~/.config/todoman/config.py``::
path = "~/.calendars/*"
The glob_ pattern in ``path`` will match all subfolders in ``~/.calendars/``,
which is exactly the tasklists we want. Now you can use ``todoman`` as
described in its documentation_ and run ``vdirsyncer sync`` to synchronize the changes to NextCloud.
.. _glob: https://en.wikipedia.org/wiki/Glob_(programming)
.. _documentation: http://todoman.readthedocs.io/
Other clients
=============
The following client applications also synchronize over CalDAV:
- The Tasks-app found on iOS
- `OpenTasks for Android <https://github.com/dmfs/opentasks>`_
- The `Tasks <https://apps.nextcloud.com/apps/tasks>`_-app for NextCloud's web UI

View file

@ -0,0 +1,23 @@
========
Xandikos
========
Xandikos_ is a lightweight, yet complete CalDAV and CardDAV server, backed by
git. Vdirsyncer is continuously tested against its latest version.
After running ``./bin/xandikos --defaults -d $HOME/dav``, you should be able to
point vdirsyncer against the root of Xandikos like this::
[storage cal]
type = "caldav"
url = "https://xandikos.example.com/"
username = "..."
password = "..."
[storage card]
type = "carddav"
url = "https://xandikos.example.com/"
username = "..."
password = "..."
.. _Xandikos: https://github.com/jelmer/xandikos

View file

@ -1,10 +1,14 @@
======================= =======================
The vdir Storage Format The Vdir Storage Format
======================= =======================
This document describes a standard for storing calendars and contacts on a This document describes a standard for storing calendars and contacts on a
filesystem, with the main goal of being easy to implement. filesystem, with the main goal of being easy to implement.
Vdirsyncer synchronizes to vdirs via :storage:`filesystem`. Each vdir
(basically just a directory with some files in it) represents a calendar or
addressbook.
Basic Structure Basic Structure
=============== ===============
@ -18,32 +22,50 @@ An item is:
- An iCalendar_ file, in which case the file extension *must* be `.ics`. - An iCalendar_ file, in which case the file extension *must* be `.ics`.
An item *should* contain a ``UID`` property as described by the vCard and An item *should* contain a ``UID`` property as described by the vCard and
iCalendar standards. iCalendar standards. If it contains more than one ``UID`` property, the values
of those *must* not differ.
The filename *must* consist of the ``ident``, followed by the file extension. The file *must* contain exactly one event, task or contact. In most cases this
The ``ident`` is either the ``UID``, if the item has one, else a string with also implies only one ``VEVENT``/``VTODO``/``VCARD`` component per file, but
similar properties as the ``UID``: e.g. recurrence exceptions would require multiple ``VEVENT`` components per
event.
Type name: UID The filename should have similar properties as the ``UID`` of the file content.
However, there is no requirement for these two to be the same. Programs may
Type purpose: To specify a value that represents a globally unique choose to store additional metadata in that filename, however, at the same time
identifier corresponding to the individual or resource associated they *must not* assume that the metadata they included will be preserved by
with the vCard. other programs.
-- The vCard_ RFC
One reason this format was chosen is due to its compatibility with the CardDAV_
and CalDAV_ standards.
.. _vCard: https://tools.ietf.org/html/rfc6350 .. _vCard: https://tools.ietf.org/html/rfc6350
.. _iCalendar: https://tools.ietf.org/html/rfc5545 .. _iCalendar: https://tools.ietf.org/html/rfc5545
.. _CardDAV: http://tools.ietf.org/html/rfc6352 .. _CardDAV: http://tools.ietf.org/html/rfc6352
.. _CalDAV: http://tools.ietf.org/search/rfc4791 .. _CalDAV: http://tools.ietf.org/search/rfc4791
Metadata
========
Any of the below metadata files may be absent. None of the files listed below
have any file extensions.
- A file called ``color`` inside the vdir indicates the vdir's color, a
property that is only relevant in UI design.
Its content is an ASCII-encoded hex-RGB value of the form ``#RRGGBB``. For
example, a file content of ``#FF0000`` indicates that the vdir has a red
(user-visible) color. No short forms or informal values such as ``red`` (as
known from CSS, for example) are allowed. The prefixing ``#`` must be
present.
- Files called ``displayname`` and ``description`` contain a UTF-8 encoded label/
description, that may be used to represent the vdir in UIs.
- A file called ``order`` inside the vdir includes the relative order
of the calendar, a property that is only relevant in UI design.
Writing to vdirs Writing to vdirs
================ ================
Creating and modifying items *should* happen atomically_. Creating and modifying items or metadata files *should* happen atomically_.
Writing to a temporary file on the same physical device, and then moving it to Writing to a temporary file on the same physical device, and then moving it to
the appropriate location is usually a very effective solution. For this the appropriate location is usually a very effective solution. For this
@ -62,8 +84,11 @@ Reading from vdirs
- The ``ident`` part of the filename *should not* be parsed to improve the - The ``ident`` part of the filename *should not* be parsed to improve the
speed of item lookup. speed of item lookup.
Rationale Considerations
========= ==============
The primary reason this format was chosen is due to its compatibility with the
CardDAV_ and CalDAV_ standards.
Performance Performance
----------- -----------
@ -74,7 +99,7 @@ collections for faster search and lookup.
The reason items' filenames don't contain any extra information is simple: The The reason items' filenames don't contain any extra information is simple: The
solutions presented induced duplication of data, where one duplicate might solutions presented induced duplication of data, where one duplicate might
become out of date because of bad implementations. As it stands right now, a become out of date because of bad implementations. As it stands right now, an
index format could be formalized separately though. index format could be formalized separately though.
vdirsyncer doesn't really have to bother about efficient item lookup, because vdirsyncer doesn't really have to bother about efficient item lookup, because

55
docs/when.rst Normal file
View file

@ -0,0 +1,55 @@
==========================
When do I need Vdirsyncer?
==========================
Why not Dropbox + todo.txt?
---------------------------
Projects like `todo.txt <http://todotxt.com/>`_ criticize the complexity of
modern productivity apps, and that rightfully. So they set out to create a new,
super-simple, human-readable format, such that vim suffices for viewing the raw
data. However, when they're faced with the question how to synchronize that
data across multiple devices, they seemed to have reached the dead end with
their novel idea: "Let's just use Dropbox".
What does file sync software do if both files have changed since the last sync?
The answer is to ignore the question, just sync as often as possible, and hope
for the best. Because if it comes to a sync conflict, most sync services are
not daring to merge files, and create two copies on each computer instead.
Merging the two task lists is left to the user.
A better idea would've been to use ``git`` to synchronize the ``todo.txt``
file, which is at least able to resolve some basic conflicts.
Why not file sync (Dropbox, git, ...) + vdir?
---------------------------------------------
Since :doc:`vdirs <vdir>` are just a bunch of files, it is obvious to try *file
synchronization* for synchronizing your data between multiple computers, such
as:
* `Syncthing <https://syncthing.net/>`_
* `Dropbox <https://dropbox.com/>`_ or one of the gajillion services like it
* `unison <https://www.cis.upenn.edu/~bcpierce/unison/>`_
* Just ``git`` with a ``sshd``.
The disadvantages of those solutions largely depend on the exact file sync
program chosen:
* Like with ``todo.txt``, Dropbox and friends are obviously agnostic/unaware of
the files' contents. If a file has changed on both sides, Dropbox just copies
both versions to both sides.
This is a good idea if the user is directly interfacing with the file system
and is able to resolve conflicts themselves. Here it might lead to
erroneous behavior with e.g. ``khal``, since there are now two events with
the same UID.
This point doesn't apply to git: It has very good merging capabilities,
better than what vdirsyncer currently has.
* Such a setup doesn't work at all with smartphones. Vdirsyncer, on the other
hand, synchronizes with CardDAV/CalDAV servers, which can be accessed with
e.g. DAVx⁵_ or other apps bundled with smartphones.
.. _DAVx⁵: https://www.davx5.com/

View file

@ -1,78 +0,0 @@
# An example configuration for vdirsyncer.
# Optional parameters are commented out.
[general]
# A folder where vdirsyncer can store some metadata about each pair.
status_path = ~/.vdirsyncer/status/
# CARDDAV
[pair bob_contacts]
# A `[pair <name>]` block defines two storages `a` and `b` that should be
# synchronized. The definition of these storages follows in `[storage <name>]`
# blocks. This is similar to accounts in OfflineIMAP.
a = bob_contacts_local
b = bob_contacts_remote
# If you want to synchronize several addressbooks, calendars etc that share
# the same storage location and differ only in a suffix to this location
# (i.e., a subdirectory) you can use collections. The comma-separated values
# in this parameter represent these subdirectories and are added as URL
# segments or similar.
# Together with the definition of the following two `[storage]` blocks below
# in this example it means that
# - https://owncloud.example.com/remote.php/carddav/addressbooks/bob/default/
# will get synced with ~/.contacts/default/
# - https://owncloud.example.com/remote.php/carddav/addressbooks/bob/work/
# will get synced with ~/.contacts/work/
# Omitting this parameter implies that the given path and URL in the
# corresponding `[storage <name>]` blocks are already pointing to a
# collection each.
collections = default,work
# To resolve a conflict the following values are possible:
# `None` - abort when collisions occur (default)
# `a wins` - assume a's items to be more up-to-date
# `b wins` - assume b's items to be more up-to-date
#conflict_resolution = None
[storage bob_contacts_local]
# A storage references actual data on a remote server or on the local disk.
# Similar to repositories in OfflineIMAP.
type = filesystem
path = ~/.contacts/
fileext = .vcf
# Create the directory if it doesn't exist: `True` or `False`
#create = True
#encoding = utf-8
[storage bob_contacts_remote]
type = carddav
url = https://owncloud.example.com/remote.php/carddav/addressbooks/bob/
# Auth types. If you know yours, set it explicitly for performance.
# - basic
# - digest
# - guess (default)
#auth = guess
#username =
# The password can also be fetched from the system password storage or netrc
#password =
# CALDAV
[pair bob_calendar]
a = bob_calendar_local
b = bob_calendar_remote
collections = private,work
[storage bob_calendar_local]
type = filesystem
path = ~/.calendars/
fileext = .ics
[storage bob_calendar_remote]
type = caldav
url = https://owncloud.example.com/remote.php/caldav/calendars/bob/
#auth = guess
#username =
#password =

29
publish-release.yaml Normal file
View file

@ -0,0 +1,29 @@
# Push new version to PyPI.
#
# Usage: hut builds submit publish-release.yaml --follow
image: alpine/edge
packages:
- py3-build
- py3-pip
- py3-setuptools
- py3-setuptools_scm
- py3-wheel
- twine
sources:
- https://github.com/pimutils/vdirsyncer
secrets:
- a36c8ba3-fba0-4338-b402-6aea0fbe771e # PyPI token.
environment:
CI: true
tasks:
- check-tag: |
cd vdirsyncer
git fetch --tags
# Stop here unless this is a tag.
git describe --exact-match --tags || complete-build
- publish: |
cd vdirsyncer
python -m build --no-isolation
twine upload --non-interactive dist/*

114
pyproject.toml Normal file
View file

@ -0,0 +1,114 @@
# Vdirsyncer synchronizes calendars and contacts.
#
# Please refer to https://vdirsyncer.pimutils.org/en/stable/packaging.html for
# how to package vdirsyncer.
[build-system]
requires = ["setuptools>=64", "setuptools_scm>=8"]
build-backend = "setuptools.build_meta"
[project]
name = "vdirsyncer"
authors = [
{name = "Markus Unterwaditzer", email = "markus@unterwaditzer.net"},
]
description = "Synchronize calendars and contacts"
readme = "README.rst"
requires-python = ">=3.9"
keywords = ["todo", "task", "icalendar", "cli"]
license = "BSD-3-Clause"
license-files = ["LICENSE"]
classifiers = [
"Development Status :: 4 - Beta",
"Environment :: Console",
"Operating System :: POSIX",
"Programming Language :: Python :: 3",
"Programming Language :: Python :: 3.10",
"Programming Language :: Python :: 3.11",
"Programming Language :: Python :: 3.12",
"Programming Language :: Python :: 3.13",
"Programming Language :: Python :: 3.9",
"Topic :: Internet",
"Topic :: Office/Business :: Scheduling",
"Topic :: Utilities",
]
dependencies = [
"click>=5.0,<9.0",
"click-log>=0.3.0,<0.5.0",
"requests>=2.20.0",
"aiohttp>=3.8.2,<4.0.0",
"aiostream>=0.4.3,<0.8.0",
"tenacity>=9.0.0",
]
dynamic = ["version"]
[project.optional-dependencies]
google = ["aiohttp-oauthlib"]
test = [
"hypothesis>=6.72.0,<7.0.0",
"pytest",
"pytest-cov",
"pytest-httpserver",
"trustme",
"pytest-asyncio",
"aioresponses",
]
docs = [
"sphinx!=1.4.7",
"sphinx_rtd_theme",
"setuptools_scm",
]
check = [
"mypy",
"ruff",
"types-docutils",
"types-requests",
"types-setuptools",
]
[project.scripts]
vdirsyncer = "vdirsyncer.cli:app"
[tool.ruff.lint]
extend-select = [
"B0",
"C4",
"E",
"I",
"RSE",
"SIM",
"TID",
"UP",
"W",
]
[tool.ruff.lint.isort]
force-single-line = true
required-imports = ["from __future__ import annotations"]
[tool.pytest.ini_options]
addopts = """
--tb=short
--cov-config .coveragerc
--cov=vdirsyncer
--cov-report=term-missing:skip-covered
--no-cov-on-fail
--color=yes
"""
# filterwarnings=error
asyncio_default_fixture_loop_scope = "function"
[tool.mypy]
ignore_missing_imports = true
[tool.coverage.report]
exclude_lines = [
"if TYPE_CHECKING:",
]
[tool.setuptools.packages.find]
include = ["vdirsyncer*"]
[tool.setuptools_scm]
write_to = "vdirsyncer/version.py"
version_scheme = "no-guess-dev"

View file

@ -0,0 +1,49 @@
#!/bin/bash
#
# This script is mean to be run inside a dedicated container,
# and not interatively.
set -ex
export DEBIAN_FRONTEND=noninteractive
apt-get update
apt-get install -y build-essential fakeroot debhelper git
apt-get install -y python3-all python3-pip python3-venv
apt-get install -y ruby ruby-dev
pip3 install virtualenv virtualenv-tools3
virtualenv -p python3 /vdirsyncer/env/
gem install fpm
# See https://github.com/jordansissel/fpm/issues/1106#issuecomment-461678970
pip3 uninstall -y virtualenv
echo 'python3 -m venv "$@"' > /usr/local/bin/virtualenv
chmod +x /usr/local/bin/virtualenv
cp -r /source/ /vdirsyncer/vdirsyncer/
cd /vdirsyncer/vdirsyncer/ || exit 2
mkdir /vdirsyncer/pkgs/
basename -- *.tar.gz .tar.gz | cut -d'-' -f2 | sed -e 's/\.dev/~/g' | tee version
# XXX: Do I really not want google support included?
(echo -n *.tar.gz; echo '[google]') | tee requirements.txt
fpm --verbose \
--input-type virtualenv \
--output-type deb \
--name "vdirsyncer-latest" \
--version "$(cat version)" \
--prefix /opt/venvs/vdirsyncer-latest \
--depends python3 \
requirements.txt
mv /vdirsyncer/vdirsyncer/*.deb /vdirsyncer/pkgs/
cd /vdirsyncer/pkgs/
dpkg -i -- *.deb
# Check that it works:
LC_ALL=C.UTF-8 LANG=C.UTF-8 /opt/venvs/vdirsyncer-latest/bin/vdirsyncer --version
cp -- *.deb /source/

56
scripts/release-deb.sh Normal file
View file

@ -0,0 +1,56 @@
#!/bin/sh
set -xeu
SCRIPT_PATH=$(realpath "$0")
SCRIPT_DIR=$(dirname "$SCRIPT_PATH")
# E.g.: debian, ubuntu
DISTRO=${DISTRO:1}
# E.g.: bullseye, bookwork
DISTROVER=${DISTROVER:2}
CONTAINER_NAME="vdirsyncer-${DISTRO}-${DISTROVER}"
CONTEXT="$(mktemp -d)"
DEST_DIR="$SCRIPT_DIR/../$DISTRO-$DISTROVER"
cleanup() {
rm -rf "$CONTEXT"
}
trap cleanup EXIT
# Prepare files.
cp scripts/_build_deb_in_container.bash "$CONTEXT"
python setup.py sdist -d "$CONTEXT"
docker run -it \
--name "$CONTAINER_NAME" \
--volume "$CONTEXT:/source" \
"$DISTRO:$DISTROVER" \
bash /source/_build_deb_in_container.bash
# Keep around the package filename.
PACKAGE=$(ls "$CONTEXT"/*.deb)
PACKAGE=$(basename "$PACKAGE")
# Save the build deb files.
mkdir -p "$DEST_DIR"
cp "$CONTEXT"/*.deb "$DEST_DIR"
echo Build complete! 🤖
# Packagecloud uses some internal IDs for each distro.
# Extract the one for the distro we're publishing.
DISTRO_ID=$(
curl -s \
https://"$PACKAGECLOUD_TOKEN":@packagecloud.io/api/v1/distributions.json | \
jq '.deb | .[] | select(.index_name=="'"$DISTRO"'") | .versions | .[] | select(.index_name=="'"$DISTROVER"'") | .id'
)
# Actually push the package.
curl \
-F "package[distro_version_id]=$DISTRO_ID" \
-F "package[package_file]=@$DEST_DIR/$PACKAGE" \
https://"$PACKAGECLOUD_TOKEN":@packagecloud.io/api/v1/repos/pimutils/vdirsyncer/packages.json
echo Done! ✨

View file

@ -1,5 +0,0 @@
[wheel]
universal = 1
[pytest]
norecursedirs = tests/storage/dav/servers/*

View file

@ -1,48 +0,0 @@
# -*- coding: utf-8 -*-
'''
vdirsyncer
~~~~~~~~~~
vdirsyncer is a synchronization tool for vdir. See the README for more
details.
:copyright: (c) 2014 Markus Unterwaditzer & contributors
:license: MIT, see LICENSE for more details.
'''
import ast
import re
from setuptools import find_packages, setup
_version_re = re.compile(r'__version__\s+=\s+(.*)')
with open('vdirsyncer/__init__.py', 'rb') as f:
version = str(ast.literal_eval(_version_re.search(
f.read().decode('utf-8')).group(1)))
setup(
name='vdirsyncer',
version=version,
author='Markus Unterwaditzer',
author_email='markus@unterwaditzer.net',
url='https://github.com/untitaker/vdirsyncer',
description='A synchronization tool for vdir',
license='MIT',
long_description=open('README.rst').read(),
packages=find_packages(exclude=['tests.*', 'tests']),
include_package_data=True,
entry_points={
'console_scripts': ['vdirsyncer = vdirsyncer.cli:main']
},
install_requires=[
'click>=2.0',
'requests',
'lxml',
'icalendar>=3.6',
'requests_toolbelt>=0.3.0'
],
extras_require={'keyring': ['keyring']}
)

View file

@ -1,37 +1,29 @@
# -*- coding: utf-8 -*- """
''' Test suite for vdirsyncer.
tests """
~~~~~
Test suite for vdirsyncer. from __future__ import annotations
:copyright: (c) 2014 Markus Unterwaditzer & contributors import hypothesis.strategies as st
:license: MIT, see LICENSE for more details. import urllib3.exceptions
'''
from vdirsyncer.utils.compat import text_type from vdirsyncer.vobject import normalize_item
from vdirsyncer.utils.vobject import normalize_item as _normalize_item
urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)
def blow_up(*a, **kw): def blow_up(*a, **kw):
raise AssertionError('Did not expect to be called.') raise AssertionError("Did not expect to be called.")
def normalize_item(item):
if not isinstance(item, text_type):
item = item.raw
return tuple(sorted(_normalize_item(
item, use_icalendar=False).splitlines()))
def assert_item_equals(a, b): def assert_item_equals(a, b):
assert normalize_item(a) == normalize_item(b) assert normalize_item(a) == normalize_item(b)
VCARD_TEMPLATE = u'''BEGIN:VCARD VCARD_TEMPLATE = """BEGIN:VCARD
VERSION:3.0 VERSION:3.0
FN:Cyrus Daboo FN:Cyrus Daboo
N:Daboo;Cyrus N:Daboo;Cyrus;;;
ADR;TYPE=POSTAL:;2822 Email HQ;Suite 2821;RFCVille;PA;15213;USA ADR;TYPE=POSTAL:;2822 Email HQ;Suite 2821;RFCVille;PA;15213;USA
EMAIL;TYPE=PREF:cyrus@example.com EMAIL;TYPE=PREF:cyrus@example.com
NICKNAME:me NICKNAME:me
@ -39,12 +31,12 @@ NOTE:Example VCard.
ORG:Self Employed ORG:Self Employed
TEL;TYPE=VOICE:412 605 0499 TEL;TYPE=VOICE:412 605 0499
TEL;TYPE=FAX:412 605 0705 TEL;TYPE=FAX:412 605 0705
URL:http://www.example.com URL;VALUE=URI:http://www.example.com
X-SOMETHING:{r} X-SOMETHING:{r}
UID:{r} UID:{uid}
END:VCARD''' END:VCARD"""
TASK_TEMPLATE = u'''BEGIN:VCALENDAR TASK_TEMPLATE = """BEGIN:VCALENDAR
VERSION:2.0 VERSION:2.0
PRODID:-//dmfs.org//mimedir.icalendar//EN PRODID:-//dmfs.org//mimedir.icalendar//EN
BEGIN:VTODO BEGIN:VTODO
@ -54,29 +46,65 @@ LAST-MODIFIED;VALUE=DATE-TIME:20140122T151338Z
SEQUENCE:2 SEQUENCE:2
SUMMARY:Book: Kowlani - Tödlicher Staub SUMMARY:Book: Kowlani - Tödlicher Staub
X-SOMETHING:{r} X-SOMETHING:{r}
UID:{r} UID:{uid}
END:VTODO END:VTODO
END:VCALENDAR''' END:VCALENDAR"""
BARE_EVENT_TEMPLATE = u'''BEGIN:VEVENT BARE_EVENT_TEMPLATE = """BEGIN:VEVENT
DTSTART:19970714T170000Z DTSTART:19970714T170000Z
DTEND:19970715T035959Z DTEND:19970715T035959Z
SUMMARY:Bastille Day Party SUMMARY:Bastille Day Party
X-SOMETHING:{r} X-SOMETHING:{r}
UID:{r} UID:{uid}
END:VEVENT''' END:VEVENT"""
EVENT_TEMPLATE = u'''BEGIN:VCALENDAR EVENT_TEMPLATE = (
"""BEGIN:VCALENDAR
VERSION:2.0 VERSION:2.0
PRODID:-//hacksw/handcal//NONSGML v1.0//EN PRODID:-//hacksw/handcal//NONSGML v1.0//EN
''' + BARE_EVENT_TEMPLATE + u''' """
END:VCALENDAR''' + BARE_EVENT_TEMPLATE
+ """
END:VCALENDAR"""
)
EVENT_WITH_TIMEZONE_TEMPLATE = (
"""BEGIN:VCALENDAR
BEGIN:VTIMEZONE
TZID:Europe/Rome
X-LIC-LOCATION:Europe/Rome
BEGIN:DAYLIGHT
TZOFFSETFROM:+0100
TZOFFSETTO:+0200
TZNAME:CEST
DTSTART:19700329T020000
RRULE:FREQ=YEARLY;BYDAY=-1SU;BYMONTH=3
END:DAYLIGHT
BEGIN:STANDARD
TZOFFSETFROM:+0200
TZOFFSETTO:+0100
TZNAME:CET
DTSTART:19701025T030000
RRULE:FREQ=YEARLY;BYDAY=-1SU;BYMONTH=10
END:STANDARD
END:VTIMEZONE
"""
+ BARE_EVENT_TEMPLATE
+ """
END:VCALENDAR"""
)
SIMPLE_TEMPLATE = u'''BEGIN:FOO SIMPLE_TEMPLATE = """BEGIN:FOO
UID:{r} UID:{uid}
X-SOMETHING:{r} X-SOMETHING:{r}
HAHA:YES HAHA:YES
END:FOO''' END:FOO"""
printable_characters_strategy = st.text(st.characters(exclude_categories=("Cc", "Cs")))
uid_strategy = st.text(
st.characters(exclude_categories=("Zs", "Zl", "Zp", "Cc", "Cs")), min_size=1
).filter(lambda x: x.strip() == x)

View file

@ -1,19 +1,70 @@
# -*- coding: utf-8 -*- """
''' General-purpose fixtures for vdirsyncer's testsuite.
tests.conftest """
~~~~~~~~~~~~~~
General-purpose fixtures for vdirsyncer's testsuite. from __future__ import annotations
:copyright: (c) 2014 Markus Unterwaditzer & contributors import logging
:license: MIT, see LICENSE for more details. import os
'''
import aiohttp
import click_log
import pytest import pytest
import pytest_asyncio
import vdirsyncer.log from hypothesis import HealthCheck
from hypothesis import Verbosity
from hypothesis import settings
@pytest.fixture(autouse=True) @pytest.fixture(autouse=True)
def setup_logging(): def setup_logging():
vdirsyncer.log.set_level(vdirsyncer.log.logging.DEBUG) click_log.basic_config("vdirsyncer").setLevel(logging.DEBUG)
vdirsyncer.log.add_handler(vdirsyncer.log.stdout_handler)
try:
import pytest_benchmark
except ImportError:
@pytest.fixture
def benchmark():
return lambda x: x()
else:
del pytest_benchmark
settings.register_profile(
"ci",
settings(
max_examples=1000,
verbosity=Verbosity.verbose,
suppress_health_check=[HealthCheck.too_slow],
),
)
settings.register_profile(
"deterministic",
settings(
derandomize=True,
suppress_health_check=list(HealthCheck),
),
)
settings.register_profile("dev", settings(suppress_health_check=[HealthCheck.too_slow]))
if os.environ.get("DETERMINISTIC_TESTS", "false").lower() == "true":
settings.load_profile("deterministic")
elif os.environ.get("CI", "false").lower() == "true":
settings.load_profile("ci")
else:
settings.load_profile("dev")
@pytest_asyncio.fixture
async def aio_session():
async with aiohttp.ClientSession() as session:
yield session
@pytest_asyncio.fixture
async def aio_connector():
async with aiohttp.TCPConnector(limit_per_host=16) as conn:
yield conn

View file

@ -1,188 +1,428 @@
# -*- coding: utf-8 -*- from __future__ import annotations
'''
tests.storage
~~~~~~~~~~~~~
:copyright: (c) 2014 Markus Unterwaditzer & contributors
:license: MIT, see LICENSE for more details.
'''
import random import random
import textwrap
import uuid
from urllib.parse import quote as urlquote
from urllib.parse import unquote as urlunquote
import aiostream
import pytest import pytest
import pytest_asyncio
import vdirsyncer.exceptions as exceptions from tests import EVENT_TEMPLATE
from vdirsyncer.storage.base import Item from tests import TASK_TEMPLATE
from vdirsyncer.utils.compat import iteritems, text_type from tests import VCARD_TEMPLATE
from tests import assert_item_equals
from .. import SIMPLE_TEMPLATE, assert_item_equals from tests import normalize_item
from vdirsyncer import exceptions
from vdirsyncer.storage.base import normalize_meta_value
from vdirsyncer.vobject import Item
class BaseStorageTests(object): def get_server_mixin(server_name):
item_template = SIMPLE_TEMPLATE from . import __name__ as base
x = __import__(f"{base}.servers.{server_name}", fromlist=[""])
return x.ServerMixin
def format_item(item_template, uid=None):
# assert that special chars are handled correctly.
r = random.random()
return Item(item_template.format(r=r, uid=uid or r))
class StorageTests:
storage_class = None
supports_collections = True
supports_metadata = True
@pytest.fixture(params=["VEVENT", "VTODO", "VCARD"])
def item_type(self, request):
"""Parametrize with all supported item types."""
return request.param
@pytest.fixture @pytest.fixture
def storage_args(self): def get_storage_args(self):
return self.get_storage_args """
Return a function with the following properties:
def get_storage_args(self, collection=None): :param collection: The name of the collection to create and use.
raise NotImplementedError() """
raise NotImplementedError
@pytest_asyncio.fixture
async def s(self, get_storage_args):
rv = self.storage_class(**await get_storage_args())
return rv
@pytest.fixture @pytest.fixture
def storage(self, storage_args): def get_item(self, item_type):
def inner(**kw): template = {
return self.storage_class(**storage_args(**kw)) "VEVENT": EVENT_TEMPLATE,
"VTODO": TASK_TEMPLATE,
"VCARD": VCARD_TEMPLATE,
}[item_type]
return inner return lambda **kw: format_item(template, **kw)
@pytest.fixture @pytest.fixture
def s(self, storage): def requires_collections(self):
return storage() if not self.supports_collections:
pytest.skip("This storage does not support collections.")
def _create_bogus_item(self, item_template=None): @pytest.fixture
r = random.random() def requires_metadata(self):
item_template = item_template or self.item_template if not self.supports_metadata:
return Item(item_template.format(r=r)) pytest.skip("This storage does not support metadata.")
def test_generic(self, s): @pytest.mark.asyncio
items = [self._create_bogus_item() for i in range(1, 10)] async def test_generic(self, s, get_item):
items = [get_item() for i in range(1, 10)]
hrefs = [] hrefs = []
for item in items: for item in items:
hrefs.append(s.upload(item)) href, etag = await s.upload(item)
if etag is None:
_, etag = await s.get(href)
hrefs.append((href, etag))
hrefs.sort() hrefs.sort()
assert hrefs == sorted(s.list()) assert hrefs == sorted(await aiostream.stream.list(s.list()))
for href, etag in hrefs: for href, etag in hrefs:
assert isinstance(href, (text_type, bytes)) assert isinstance(href, (str, bytes))
assert isinstance(etag, (text_type, bytes)) assert isinstance(etag, (str, bytes))
assert s.has(href) assert await s.has(href)
item, etag2 = s.get(href) item, etag2 = await s.get(href)
assert etag == etag2 assert etag == etag2
def test_empty_get_multi(self, s): @pytest.mark.asyncio
assert list(s.get_multi([])) == [] async def test_empty_get_multi(self, s):
assert await aiostream.stream.list(s.get_multi([])) == []
def test_upload_already_existing(self, s): @pytest.mark.asyncio
item = self._create_bogus_item() async def test_get_multi_duplicates(self, s, get_item):
s.upload(item) href, etag = await s.upload(get_item())
if etag is None:
_, etag = await s.get(href)
((href2, _item, etag2),) = await aiostream.stream.list(s.get_multi([href] * 2))
assert href2 == href
assert etag2 == etag
@pytest.mark.asyncio
async def test_upload_already_existing(self, s, get_item):
item = get_item()
await s.upload(item)
with pytest.raises(exceptions.PreconditionFailed): with pytest.raises(exceptions.PreconditionFailed):
s.upload(item) await s.upload(item)
def test_upload(self, s): @pytest.mark.asyncio
item = self._create_bogus_item() async def test_upload(self, s, get_item):
href, etag = s.upload(item) item = get_item()
assert_item_equals(s.get(href)[0], item) href, _etag = await s.upload(item)
assert_item_equals((await s.get(href))[0], item)
def test_update(self, s): @pytest.mark.asyncio
item = self._create_bogus_item() async def test_update(self, s, get_item):
href, etag = s.upload(item) item = get_item()
assert_item_equals(s.get(href)[0], item) href, etag = await s.upload(item)
if etag is None:
_, etag = await s.get(href)
assert_item_equals((await s.get(href))[0], item)
new_item = self._create_bogus_item() new_item = get_item(uid=item.uid)
new_etag = s.update(href, new_item, etag) new_etag = await s.update(href, new_item, etag)
# See https://github.com/untitaker/vdirsyncer/issues/48 if new_etag is None:
assert isinstance(new_etag, (bytes, text_type)) _, new_etag = await s.get(href)
assert_item_equals(s.get(href)[0], new_item) # See https://github.com/pimutils/vdirsyncer/issues/48
assert isinstance(new_etag, (bytes, str))
assert_item_equals((await s.get(href))[0], new_item)
def test_update_nonexisting(self, s): @pytest.mark.asyncio
item = self._create_bogus_item() async def test_update_nonexisting(self, s, get_item):
item = get_item()
with pytest.raises(exceptions.PreconditionFailed): with pytest.raises(exceptions.PreconditionFailed):
s.update(s._get_href(item), item, '"123"') await s.update("huehue", item, '"123"')
@pytest.mark.asyncio
async def test_wrong_etag(self, s, get_item):
item = get_item()
href, _etag = await s.upload(item)
with pytest.raises(exceptions.PreconditionFailed): with pytest.raises(exceptions.PreconditionFailed):
s.update('huehue', item, '"123"') await s.update(href, item, '"lolnope"')
def test_wrong_etag(self, s):
item = self._create_bogus_item()
href, etag = s.upload(item)
with pytest.raises(exceptions.PreconditionFailed): with pytest.raises(exceptions.PreconditionFailed):
s.update(href, item, '"lolnope"') await s.delete(href, '"lolnope"')
@pytest.mark.asyncio
async def test_delete(self, s, get_item):
href, etag = await s.upload(get_item())
await s.delete(href, etag)
assert not await aiostream.stream.list(s.list())
@pytest.mark.asyncio
async def test_delete_nonexisting(self, s, get_item):
with pytest.raises(exceptions.PreconditionFailed): with pytest.raises(exceptions.PreconditionFailed):
s.delete(href, '"lolnope"') await s.delete("1", '"123"')
def test_delete(self, s): @pytest.mark.asyncio
href, etag = s.upload(self._create_bogus_item()) async def test_list(self, s, get_item):
s.delete(href, etag) assert not await aiostream.stream.list(s.list())
assert not list(s.list()) href, etag = await s.upload(get_item())
if etag is None:
_, etag = await s.get(href)
assert await aiostream.stream.list(s.list()) == [(href, etag)]
def test_delete_nonexisting(self, s): @pytest.mark.asyncio
with pytest.raises(exceptions.PreconditionFailed): async def test_has(self, s, get_item):
s.delete('1', '"123"') assert not await s.has("asd")
href, etag = await s.upload(get_item())
assert await s.has(href)
assert not await s.has("asd")
await s.delete(href, etag)
assert not await s.has(href)
def test_list(self, s): @pytest.mark.asyncio
assert not list(s.list()) async def test_update_others_stay_the_same(self, s, get_item):
s.upload(self._create_bogus_item()) info = {}
assert list(s.list()) for _ in range(4):
href, etag = await s.upload(get_item())
if etag is None:
_, etag = await s.get(href)
info[href] = etag
def test_has(self, s): items = await aiostream.stream.list(
assert not s.has('asd') s.get_multi(href for href, etag in info.items())
href, etag = s.upload(self._create_bogus_item()) )
assert s.has(href) assert {href: etag for href, item, etag in items} == info
assert not s.has('asd')
def test_update_others_stay_the_same(self, s):
info = dict([
s.upload(self._create_bogus_item()),
s.upload(self._create_bogus_item()),
s.upload(self._create_bogus_item()),
s.upload(self._create_bogus_item())
])
assert dict(
(href, etag) for href, item, etag
in s.get_multi(href for href, etag in iteritems(info))
) == info
def test_repr(self, s): def test_repr(self, s):
assert self.storage_class.__name__ in repr(s) assert self.storage_class.__name__ in repr(s)
assert s.instance_name is None
@pytest.mark.asyncio
class SupportsCollections(object): async def test_discover(
self,
def test_discover(self, storage_args): requires_collections,
get_storage_args,
get_item,
aio_connector,
):
collections = set() collections = set()
for i in range(1, 5):
collection = f"test{i}"
s = self.storage_class(**await get_storage_args(collection=collection))
assert not await aiostream.stream.list(s.list())
await s.upload(get_item())
collections.add(s.collection)
def main(): discovered = await aiostream.stream.list(
for i in range(1, 5): self.storage_class.discover(**await get_storage_args(collection=None))
collection = 'test{}'.format(i) )
# Create collections on-the-fly for most storages actual = {c["collection"] for c in discovered}
# Except ownCloud, which already has all of them, and more
i += 1
s = self.storage_class(**storage_args(collection=collection))
# radicale ignores empty collections during discovery assert actual >= collections
item = self._create_bogus_item()
s.upload(item)
collections.add(s.collection) @pytest.mark.asyncio
main() # remove leftover variables from loop for safety async def test_create_collection(
self,
requires_collections,
get_storage_args,
get_item,
):
if getattr(self, "dav_server", "") in ("icloud", "fastmail", "davical"):
pytest.skip("Manual cleanup would be necessary.")
if getattr(self, "dav_server", "") == "radicale":
pytest.skip("Radicale does not support collection creation")
d = self.storage_class.discover( args = await get_storage_args(collection=None)
**storage_args(collection=None)) args["collection"] = "test"
def main(): s = self.storage_class(**await self.storage_class.create_collection(**args))
for s in d:
if s.collection not in collections:
# ownCloud has many more collections, as on-the-fly
# creation doesn't really work there. Skip those
# collections, as they are not relevant to us.
print('Skipping {}'.format(s.collection))
continue
collections.remove(s.collection)
main()
assert not collections href = (await s.upload(get_item()))[0]
assert href in await aiostream.stream.list(
(href async for href, etag in s.list())
)
def test_discover_collection_arg(self, storage_args): @pytest.mark.asyncio
args = storage_args(collection='test2') async def test_discover_collection_arg(
self, requires_collections, get_storage_args
):
args = await get_storage_args(collection="test2")
with pytest.raises(TypeError) as excinfo: with pytest.raises(TypeError) as excinfo:
list(self.storage_class.discover(**args)) await aiostream.stream.list(self.storage_class.discover(**args))
assert 'collection argument must not be given' in str(excinfo.value) assert "collection argument must not be given" in str(excinfo.value)
def test_collection_arg(self, storage): @pytest.mark.asyncio
s = storage(collection='test2') async def test_collection_arg(self, get_storage_args):
# Can't do stronger assertion because of radicale, which needs a if self.supports_collections:
# fileextension to guess the collection type. s = self.storage_class(**await get_storage_args(collection="test2"))
assert 'test2' in s.collection # Can't do stronger assertion because of radicale, which needs a
# fileextension to guess the collection type.
assert "test2" in s.collection
else:
with pytest.raises(ValueError):
self.storage_class(collection="ayy", **await get_storage_args())
@pytest.mark.asyncio
async def test_case_sensitive_uids(self, s, get_item):
if s.storage_name == "filesystem":
pytest.skip("Behavior depends on the filesystem.")
class StorageTests(BaseStorageTests, SupportsCollections): uid = str(uuid.uuid4())
pass await s.upload(get_item(uid=uid.upper()))
await s.upload(get_item(uid=uid.lower()))
items = [href async for href, etag in s.list()]
assert len(items) == 2
assert len(set(items)) == 2
@pytest.mark.asyncio
async def test_specialchars(
self, monkeypatch, requires_collections, get_storage_args, get_item
):
if getattr(self, "dav_server", "") in ("icloud", "fastmail"):
pytest.skip("iCloud and FastMail reject this name.")
monkeypatch.setattr("vdirsyncer.utils.generate_href", lambda x: x)
uid = "test @ foo ät bar град сатану"
collection = "test @ foo ät bar"
s = self.storage_class(**await get_storage_args(collection=collection))
item = get_item(uid=uid)
href, etag = await s.upload(item)
item2, etag2 = await s.get(href)
if etag is not None:
assert etag2 == etag
assert_item_equals(item2, item)
((_, etag3),) = await aiostream.stream.list(s.list())
assert etag2 == etag3
assert collection in urlunquote(s.collection)
if self.storage_class.storage_name.endswith("dav"):
assert urlquote(uid, "/@:") in href
@pytest.mark.asyncio
async def test_newline_in_uid(
self, monkeypatch, requires_collections, get_storage_args, get_item
):
monkeypatch.setattr("vdirsyncer.utils.generate_href", lambda x: x)
uid = "UID:20210609T084907Z-@synaps-web-54fddfdf7-7kcfm%0A.ics"
s = self.storage_class(**await get_storage_args())
item = get_item(uid=uid)
href, etag = await s.upload(item)
item2, etag2 = await s.get(href)
if etag is not None:
assert etag2 == etag
assert_item_equals(item2, item)
((_, etag3),) = await aiostream.stream.list(s.list())
assert etag2 == etag3
@pytest.mark.asyncio
async def test_empty_metadata(self, requires_metadata, s):
if getattr(self, "dav_server", ""):
pytest.skip()
assert await s.get_meta("color") is None
assert await s.get_meta("displayname") is None
@pytest.mark.asyncio
async def test_metadata(self, requires_metadata, s):
if getattr(self, "dav_server", "") == "xandikos":
pytest.skip("xandikos does not support removing metadata.")
try:
await s.set_meta("color", None)
assert await s.get_meta("color") is None
await s.set_meta("color", "#ff0000")
assert await s.get_meta("color") == "#ff0000"
except exceptions.UnsupportedMetadataError:
pass
@pytest.mark.asyncio
async def test_encoding_metadata(self, requires_metadata, s):
for x in ("hello world", "hello wörld"):
await s.set_meta("displayname", x)
rv = await s.get_meta("displayname")
assert rv == x
assert isinstance(rv, str)
@pytest.mark.parametrize(
"value",
[
None,
"",
"Hello there!",
"Österreich",
"中国",
"한글",
"42a4ec99-b1c2-4859-b142-759112f2ca50",
"فلسطين",
],
)
@pytest.mark.asyncio
async def test_metadata_normalization(self, requires_metadata, s, value):
x = await s.get_meta("displayname")
assert x == normalize_meta_value(x)
if not getattr(self, "dav_server", None):
# ownCloud replaces "" with "unnamed"
await s.set_meta("displayname", value)
assert await s.get_meta("displayname") == normalize_meta_value(value)
@pytest.mark.asyncio
async def test_recurring_events(self, s, item_type):
if item_type != "VEVENT":
pytest.skip("This storage instance doesn't support iCalendar.")
uid = str(uuid.uuid4())
item = Item(
textwrap.dedent(
f"""
BEGIN:VCALENDAR
VERSION:2.0
BEGIN:VEVENT
DTSTART;TZID=UTC:20140325T084000Z
DTEND;TZID=UTC:20140325T101000Z
DTSTAMP:20140327T060506Z
UID:{uid}
RECURRENCE-ID;TZID=UTC:20140325T083000Z
CREATED:20131216T033331Z
DESCRIPTION:
LAST-MODIFIED:20140327T060215Z
LOCATION:
SEQUENCE:1
STATUS:CONFIRMED
SUMMARY:test Event
TRANSP:OPAQUE
END:VEVENT
BEGIN:VEVENT
DTSTART;TZID=UTC:20140128T083000Z
DTEND;TZID=UTC:20140128T100000Z
RRULE:FREQ=WEEKLY;BYDAY=TU;UNTIL=20141208T213000Z
DTSTAMP:20140327T060506Z
UID:{uid}
CREATED:20131216T033331Z
DESCRIPTION:
LAST-MODIFIED:20140222T101012Z
LOCATION:
SEQUENCE:0
STATUS:CONFIRMED
SUMMARY:Test event
TRANSP:OPAQUE
END:VEVENT
END:VCALENDAR
"""
).strip()
)
href, _etag = await s.upload(item)
item2, _etag2 = await s.get(href)
assert normalize_item(item) == normalize_item(item2)

116
tests/storage/conftest.py Normal file
View file

@ -0,0 +1,116 @@
from __future__ import annotations
import asyncio
import contextlib
import subprocess
import time
import uuid
import aiostream
import pytest
import pytest_asyncio
import requests
def wait_for_container(url):
"""Wait for a container to initialise.
Polls a URL every 100ms until the server responds.
"""
# give the server 5 seconds to settle
for _ in range(50):
print(_)
try:
response = requests.get(url)
response.raise_for_status()
except requests.ConnectionError:
pass
else:
return
time.sleep(0.1)
pytest.exit(
"Server did not initialise in 5 seconds.\n"
"WARNING: There may be a stale docker container still running."
)
@contextlib.contextmanager
def dockerised_server(name, container_port, exposed_port):
"""Run a dockerised DAV server as a contenxt manager."""
container_id = None
url = f"http://127.0.0.1:{exposed_port}/"
try:
# Hint: This will block while the pull happends, and only return once
# the container has actually started.
output = subprocess.check_output(
[
"docker",
"run",
"--rm",
"--detach",
"--publish",
f"{exposed_port}:{container_port}",
f"whynothugo/vdirsyncer-devkit-{name}",
]
)
container_id = output.decode().strip()
wait_for_container(url)
yield url
finally:
if container_id:
subprocess.check_output(["docker", "kill", container_id])
@pytest.fixture(scope="session")
def baikal_server():
with dockerised_server("baikal", "80", "8002"):
yield
@pytest.fixture(scope="session")
def radicale_server():
with dockerised_server("radicale", "8001", "8001"):
yield
@pytest.fixture(scope="session")
def xandikos_server():
with dockerised_server("xandikos", "8000", "8000"):
yield
@pytest_asyncio.fixture
async def slow_create_collection(request, aio_connector):
# We need to properly clean up because otherwise we might run into
# storage limits.
to_delete = []
async def inner(cls: type, args: dict, collection_name: str) -> dict:
"""Create a collection
Returns args necessary to create a Storage instance pointing to it.
"""
assert collection_name.startswith("test")
# Make each name unique
collection_name = f"{collection_name}-vdirsyncer-ci-{uuid.uuid4()}"
# Create the collection:
args = await cls.create_collection(collection_name, **args)
collection = cls(**args)
# Keep collection in a list to be deleted once tests end:
to_delete.append(collection)
assert not await aiostream.stream.list(collection.list())
return args
yield inner
await asyncio.gather(*(c.session.request("DELETE", "") for c in to_delete))

View file

@ -1,8 +1,53 @@
# -*- coding: utf-8 -*- from __future__ import annotations
'''
tests.storage.dav
~~~~~~~~~~~~~~~~~
:copyright: (c) 2014 Markus Unterwaditzer & contributors import os
:license: MIT, see LICENSE for more details. import uuid
'''
import aiohttp
import aiostream
import pytest
from tests import assert_item_equals
from tests.storage import StorageTests
from tests.storage import get_server_mixin
from vdirsyncer import exceptions
from vdirsyncer.vobject import Item
dav_server = os.environ.get("DAV_SERVER", "skip")
ServerMixin = get_server_mixin(dav_server)
class DAVStorageTests(ServerMixin, StorageTests):
dav_server = dav_server
@pytest.mark.skipif(dav_server == "radicale", reason="Radicale is very tolerant.")
@pytest.mark.asyncio
async def test_dav_broken_item(self, s):
item = Item("HAHA:YES")
with pytest.raises((exceptions.Error, aiohttp.ClientResponseError)):
await s.upload(item)
assert not await aiostream.stream.list(s.list())
@pytest.mark.asyncio
async def test_dav_empty_get_multi_performance(self, s, monkeypatch):
def breakdown(*a, **kw):
raise AssertionError("Expected not to be called.")
monkeypatch.setattr("requests.sessions.Session.request", breakdown)
try:
assert list(await aiostream.stream.list(s.get_multi([]))) == []
finally:
# Make sure monkeypatch doesn't interfere with DAV server teardown
monkeypatch.undo()
@pytest.mark.asyncio
async def test_dav_unicode_href(self, s, get_item, monkeypatch):
if self.dav_server == "radicale":
pytest.skip("Radicale is unable to deal with unicode hrefs")
monkeypatch.setattr(s, "_get_href", lambda item: item.ident + s.fileext)
item = get_item(uid="град сатану" + str(uuid.uuid4()))
href, _etag = await s.upload(item)
item2, _etag2 = await s.get(href)
assert_item_equals(item, item2)

View file

@ -1,8 +0,0 @@
# -*- coding: utf-8 -*-
'''
tests.storage.dav.servers
~~~~~~~~~~~~~~~~~~~~~~~~~
:copyright: (c) 2014 Markus Unterwaditzer & contributors
:license: MIT, see LICENSE for more details.
'''

View file

@ -1,108 +0,0 @@
# -*- coding: utf-8 -*-
import os
import sys
import pytest
import wsgi_intercept
import wsgi_intercept.requests_intercept
wsgi_intercept.requests_intercept.install()
RADICALE_SCHEMA = '''
create table collection (
path varchar(200) not null,
parent_path varchar(200) references collection (path),
primary key (path));
create table item (
name varchar(200) not null,
tag text not null,
collection_path varchar(200) references collection (path),
primary key (name));
create table header (
name varchar(200) not null,
value text not null,
collection_path varchar(200) references collection (path),
primary key (name, collection_path));
create table line (
name text not null,
value text not null,
item_name varchar(200) references item (name),
timestamp bigint not null,
primary key (timestamp));
create table property (
name varchar(200) not null,
value text not null,
collection_path varchar(200) references collection (path),
primary key (name, collection_path));
'''.split(';')
storage_backend = os.environ.get('RADICALE_BACKEND', '') or 'filesystem'
def do_the_radicale_dance(tmpdir):
# All of radicale is already global state, the cleanliness of the code and
# all hope is already lost. This function runs before every test.
# This wipes out the radicale modules, to reset all of its state.
for module in list(sys.modules):
if module.startswith('radicale'):
del sys.modules[module]
# radicale.config looks for this envvar. We have to delete it before it
# tries to load a config file.
os.environ['RADICALE_CONFIG'] = ''
import radicale.config
# Now we can set some basic configuration.
radicale.config.set('rights', 'type', 'owner_only')
radicale.config.set('auth', 'type', 'http')
import radicale.auth.http
def is_authenticated(user, password):
return user == 'bob' and password == 'bob'
radicale.auth.http.is_authenticated = is_authenticated
if storage_backend == 'filesystem':
radicale.config.set('storage', 'type', 'filesystem')
radicale.config.set('storage', 'filesystem_folder', tmpdir)
elif storage_backend == 'database':
radicale.config.set('storage', 'type', 'database')
radicale.config.set('storage', 'database_url', 'sqlite://')
from radicale.storage import database
s = database.Session()
for line in RADICALE_SCHEMA:
s.execute(line)
s.commit()
else:
raise RuntimeError()
class ServerMixin(object):
@pytest.fixture(autouse=True)
def setup(self, request, tmpdir):
do_the_radicale_dance(str(tmpdir))
from radicale import Application
wsgi_intercept.add_wsgi_intercept('127.0.0.1', 80, Application)
def teardown():
wsgi_intercept.remove_wsgi_intercept('127.0.0.1', 80)
request.addfinalizer(teardown)
def get_storage_args(self, collection='test'):
url = 'http://127.0.0.1/bob/'
if collection is not None:
collection += self.storage_class.fileext
return {'url': url, 'username': 'bob', 'password': 'bob',
'collection': collection}

View file

@ -1,18 +0,0 @@
#!/bin/sh
set -e
[ -n "$REQUIREMENTS" ] || export REQUIREMENTS=release
[ -n "$RADICALE_BACKEND" ] || export RADICALE_BACKEND=filesystem
if [ "$REQUIREMENTS" = "release" ]; then
radicale_pkg="radicale"
elif [ "$REQUIREMENTS" = "devel" ]; then
radicale_pkg="git+https://github.com/Kozea/Radicale.git"
else
echo "Invalid requirements envvar"
false
fi
pip install wsgi_intercept $radicale_pkg
if [ "$RADICALE_BACKEND" = "database" ]; then
pip install sqlalchemy
fi

View file

@ -0,0 +1,174 @@
from __future__ import annotations
import contextlib
import datetime
from textwrap import dedent
import aiohttp
import aiostream
import pytest
from aioresponses import aioresponses
from tests import EVENT_TEMPLATE
from tests import TASK_TEMPLATE
from tests import VCARD_TEMPLATE
from tests.storage import format_item
from vdirsyncer import exceptions
from vdirsyncer.storage.dav import CalDAVStorage
from . import DAVStorageTests
from . import dav_server
class TestCalDAVStorage(DAVStorageTests):
storage_class = CalDAVStorage
@pytest.fixture(params=["VTODO", "VEVENT"])
def item_type(self, request):
return request.param
@pytest.mark.asyncio
async def test_doesnt_accept_vcard(self, item_type, get_storage_args):
s = self.storage_class(item_types=(item_type,), **await get_storage_args())
# Most storages hard-fail, but xandikos doesn't.
with contextlib.suppress(exceptions.Error, aiohttp.ClientResponseError):
await s.upload(format_item(VCARD_TEMPLATE))
assert not await aiostream.stream.list(s.list())
# The `arg` param is not named `item_types` because that would hit
# https://bitbucket.org/pytest-dev/pytest/issue/745/
@pytest.mark.parametrize(
("arg", "calls_num"),
[
(("VTODO",), 1),
(("VEVENT",), 1),
(("VTODO", "VEVENT"), 2),
(("VTODO", "VEVENT", "VJOURNAL"), 3),
((), 1),
],
)
@pytest.mark.xfail(dav_server == "baikal", reason="Baikal returns 500.")
@pytest.mark.asyncio
async def test_item_types_performance(
self, get_storage_args, arg, calls_num, monkeypatch
):
s = self.storage_class(item_types=arg, **await get_storage_args())
old_parse = s._parse_prop_responses
calls = []
def new_parse(*a, **kw):
calls.append(None)
return old_parse(*a, **kw)
monkeypatch.setattr(s, "_parse_prop_responses", new_parse)
await aiostream.stream.list(s.list())
assert len(calls) == calls_num
@pytest.mark.xfail(
dav_server == "radicale", reason="Radicale doesn't support timeranges."
)
@pytest.mark.asyncio
async def test_timerange_correctness(self, get_storage_args):
start_date = datetime.datetime(2013, 9, 10)
end_date = datetime.datetime(2013, 9, 13)
s = self.storage_class(
start_date=start_date, end_date=end_date, **await get_storage_args()
)
too_old_item = format_item(
dedent(
"""
BEGIN:VCALENDAR
VERSION:2.0
PRODID:-//hacksw/handcal//NONSGML v1.0//EN
BEGIN:VEVENT
DTSTART:19970714T170000Z
DTEND:19970715T035959Z
SUMMARY:Bastille Day Party
X-SOMETHING:{r}
UID:{r}
END:VEVENT
END:VCALENDAR
"""
).strip()
)
too_new_item = format_item(
dedent(
"""
BEGIN:VCALENDAR
VERSION:2.0
PRODID:-//hacksw/handcal//NONSGML v1.0//EN
BEGIN:VEVENT
DTSTART:20150714T170000Z
DTEND:20150715T035959Z
SUMMARY:Another Bastille Day Party
X-SOMETHING:{r}
UID:{r}
END:VEVENT
END:VCALENDAR
"""
).strip()
)
good_item = format_item(
dedent(
"""
BEGIN:VCALENDAR
VERSION:2.0
PRODID:-//hacksw/handcal//NONSGML v1.0//EN
BEGIN:VEVENT
DTSTART:20130911T170000Z
DTEND:20130912T035959Z
SUMMARY:What's with all these Bastille Day Partys
X-SOMETHING:{r}
UID:{r}
END:VEVENT
END:VCALENDAR
"""
).strip()
)
await s.upload(too_old_item)
await s.upload(too_new_item)
expected_href, _ = await s.upload(good_item)
((actual_href, _),) = await aiostream.stream.list(s.list())
assert actual_href == expected_href
@pytest.mark.asyncio
async def test_invalid_resource(self, monkeypatch, get_storage_args):
args = await get_storage_args(collection=None)
with aioresponses() as m:
m.add(args["url"], method="PROPFIND", status=200, body="Hello world")
with pytest.raises(ValueError):
s = self.storage_class(**args)
await aiostream.stream.list(s.list())
assert len(m.requests) == 1
@pytest.mark.skipif(dav_server == "icloud", reason="iCloud only accepts VEVENT")
@pytest.mark.skipif(
dav_server == "fastmail", reason="Fastmail has non-standard hadling of VTODOs."
)
@pytest.mark.xfail(dav_server == "baikal", reason="Baikal returns 500.")
@pytest.mark.asyncio
async def test_item_types_general(self, s):
event = (await s.upload(format_item(EVENT_TEMPLATE)))[0]
task = (await s.upload(format_item(TASK_TEMPLATE)))[0]
s.item_types = ("VTODO", "VEVENT")
async def hrefs():
return {href async for href, etag in s.list()}
assert await hrefs() == {event, task}
s.item_types = ("VTODO",)
assert await hrefs() == {task}
s.item_types = ("VEVENT",)
assert await hrefs() == {event}
s.item_types = ()
assert await hrefs() == {event, task}

View file

@ -0,0 +1,15 @@
from __future__ import annotations
import pytest
from vdirsyncer.storage.dav import CardDAVStorage
from . import DAVStorageTests
class TestCardDAVStorage(DAVStorageTests):
storage_class = CardDAVStorage
@pytest.fixture(params=["VCARD"])
def item_type(self, request):
return request.param

View file

@ -1,217 +1,59 @@
# -*- coding: utf-8 -*- from __future__ import annotations
'''
tests.storage.dav.test_main
~~~~~~~~~~~~~~~~~~~~~~~~~~~
:copyright: (c) 2014 Markus Unterwaditzer & contributors
:license: MIT, see LICENSE for more details.
'''
import datetime
import os
from textwrap import dedent
import pytest import pytest
import requests from vdirsyncer.storage.dav import _BAD_XML_CHARS
import requests.exceptions from vdirsyncer.storage.dav import _merge_xml
from vdirsyncer.storage.dav import _normalize_href
from tests import EVENT_TEMPLATE, TASK_TEMPLATE, VCARD_TEMPLATE from vdirsyncer.storage.dav import _parse_xml
import vdirsyncer.exceptions as exceptions
from vdirsyncer.storage.base import Item
from vdirsyncer.storage.dav import CaldavStorage, CarddavStorage
from .. import StorageTests
dav_server = os.environ.get('DAV_SERVER', '').strip() or 'radicale' def test_xml_utilities():
x = _parse_xml(
b"""<?xml version="1.0" encoding="UTF-8" ?>
<multistatus xmlns="DAV:">
<response>
<propstat>
<status>HTTP/1.1 404 Not Found</status>
<prop>
<getcontenttype/>
</prop>
</propstat>
<propstat>
<prop>
<resourcetype>
<collection/>
</resourcetype>
</prop>
</propstat>
</response>
</multistatus>
"""
)
response = x.find("{DAV:}response")
props = _merge_xml(response.findall("{DAV:}propstat/{DAV:}prop"))
assert props.find("{DAV:}resourcetype/{DAV:}collection") is not None
assert props.find("{DAV:}getcontenttype") is not None
def _get_server_mixin(server_name): @pytest.mark.parametrize("char", range(32))
from . import __name__ as base def test_xml_specialchars(char):
x = __import__('{}.servers.{}'.format(base, server_name), fromlist=['']) x = _parse_xml(
return x.ServerMixin '<?xml version="1.0" encoding="UTF-8" ?>'
f"<foo>ye{chr(char)}s\r\n"
"hello</foo>".encode("ascii")
)
ServerMixin = _get_server_mixin(dav_server) if char in _BAD_XML_CHARS:
assert x.text == "yes\nhello"
templates = { @pytest.mark.parametrize(
'VCARD': VCARD_TEMPLATE, "href",
'VEVENT': EVENT_TEMPLATE, [
'VTODO': TASK_TEMPLATE "/dav/calendars/user/testuser/123/UID%253A20210609T084907Z-@synaps-web-54fddfdf7-7kcfm%250A.ics",
} ],
)
def test_normalize_href(href):
class DavStorageTests(ServerMixin, StorageTests): assert href == _normalize_href("https://example.com", href)
def test_dav_broken_item(self, s):
item = Item(u'HAHA:YES')
try:
s.upload(item)
except (exceptions.Error, requests.exceptions.HTTPError):
pass
assert not list(s.list())
def test_wrong_etag(self, s):
super(DavStorageTests, self).test_wrong_etag(s)
def test_update_nonexisting(self, s):
super(DavStorageTests, self).test_update_nonexisting(s)
def test_dav_empty_get_multi_performance(self, s, monkeypatch):
def breakdown(*a, **kw):
raise AssertionError('Expected not to be called.')
monkeypatch.setattr('requests.sessions.Session.request', breakdown)
assert list(s.get_multi([])) == []
class TestCaldavStorage(DavStorageTests):
storage_class = CaldavStorage
item_template = TASK_TEMPLATE
def test_both_vtodo_and_vevent(self, s):
task = self._create_bogus_item(item_template=TASK_TEMPLATE)
event = self._create_bogus_item(item_template=EVENT_TEMPLATE)
href_etag_task = s.upload(task)
href_etag_event = s.upload(event)
assert set(s.list()) == set([
href_etag_task,
href_etag_event
])
@pytest.mark.parametrize('item_type', ['VTODO', 'VEVENT'])
def test_item_types_correctness(self, item_type, storage_args):
other_item_type = 'VTODO' if item_type == 'VEVENT' else 'VEVENT'
s = self.storage_class(item_types=(item_type,), **storage_args())
try:
s.upload(self._create_bogus_item(
item_template=templates[other_item_type]))
s.upload(self._create_bogus_item(
item_template=templates[other_item_type]))
except (exceptions.Error, requests.exceptions.HTTPError):
pass
href, etag = \
s.upload(self._create_bogus_item(
item_template=templates[item_type]))
((href2, etag2),) = s.list()
assert href2 == href
assert etag2 == etag
@pytest.mark.parametrize('item_types', [
('VTODO',),
('VEVENT',),
('VTODO', 'VEVENT'),
('VTODO', 'VEVENT', 'VJOURNAL'),
()
])
def test_item_types_performance(self, storage_args, item_types,
monkeypatch):
s = self.storage_class(item_types=item_types, **storage_args())
item = self._create_bogus_item()
href, etag = s.upload(item)
old_dav_query = s._dav_query
calls = []
def _dav_query(*a, **kw):
calls.append(None)
return old_dav_query(*a, **kw)
monkeypatch.setattr(s, '_dav_query', _dav_query)
rv = list(s.list())
if (dav_server != 'radicale' and not s.item_types) \
or item.parsed.name in s.item_types:
assert rv == [(href, etag)]
assert len(calls) == (len(item_types) or 1)
@pytest.mark.xfail(dav_server == 'radicale',
reason='Radicale doesn\'t support timeranges.')
def test_timerange_correctness(self, storage_args):
start_date = datetime.datetime(2013, 9, 10)
end_date = datetime.datetime(2013, 9, 13)
s = self.storage_class(start_date=start_date, end_date=end_date,
**storage_args())
too_old_item = self._create_bogus_item(item_template=dedent(u'''
BEGIN:VCALENDAR
VERSION:2.0
PRODID:-//hacksw/handcal//NONSGML v1.0//EN
BEGIN:VEVENT
DTSTART:19970714T170000Z
DTEND:19970715T035959Z
SUMMARY:Bastille Day Party
X-SOMETHING:{r}
UID:{r}
END:VEVENT
END:VCALENDAR
''').strip())
too_new_item = self._create_bogus_item(item_template=dedent(u'''
BEGIN:VCALENDAR
VERSION:2.0
PRODID:-//hacksw/handcal//NONSGML v1.0//EN
BEGIN:VEVENT
DTSTART:20150714T170000Z
DTEND:20150715T035959Z
SUMMARY:Another Bastille Day Party
X-SOMETHING:{r}
UID:{r}
END:VEVENT
END:VCALENDAR
''').strip())
good_item = self._create_bogus_item(item_template=dedent(u'''
BEGIN:VCALENDAR
VERSION:2.0
PRODID:-//hacksw/handcal//NONSGML v1.0//EN
BEGIN:VEVENT
DTSTART:20130911T170000Z
DTEND:20130912T035959Z
SUMMARY:What's with all these Bastille Day Partys
X-SOMETHING:{r}
UID:{r}
END:VEVENT
END:VCALENDAR
''').strip())
s.upload(too_old_item)
s.upload(too_new_item)
href, etag = s.upload(good_item)
assert list(s.list()) == [(href, etag)]
def test_item_types_passed_as_string(self, storage_args):
kw = storage_args()
a = self.storage_class(item_types='VTODO,VEVENT', **kw)
b = self.storage_class(item_types=('VTODO', 'VEVENT'), **kw)
assert a.item_types == b.item_types == ('VTODO', 'VEVENT')
def test_invalid_resource(self, monkeypatch, storage_args):
calls = []
args = storage_args(collection=None)
def request(session, method, url, data=None, headers=None, auth=None,
verify=None):
assert url == args['url']
calls.append(None)
r = requests.Response()
r.status_code = 200
r._content = 'Hello World.'
return r
monkeypatch.setattr('requests.sessions.Session.request', request)
with pytest.raises(ValueError):
s = self.storage_class(**args)
list(s.list())
assert len(calls) == 1
class TestCarddavStorage(DavStorageTests):
storage_class = CarddavStorage
item_template = VCARD_TEMPLATE

View file

View file

@ -0,0 +1,38 @@
from __future__ import annotations
import pytest
class ServerMixin:
@pytest.fixture
def get_storage_args(
self,
request,
tmpdir,
slow_create_collection,
baikal_server,
aio_connector,
):
async def inner(collection="test"):
base_url = "http://127.0.0.1:8002/"
args = {
"url": base_url,
"username": "baikal",
"password": "baikal",
"connector": aio_connector,
}
if self.storage_class.fileext == ".vcf":
args["url"] = base_url + "card.php/"
else:
args["url"] = base_url + "cal.php/"
if collection is not None:
args = await slow_create_collection(
self.storage_class,
args,
collection,
)
return args
return inner

View file

@ -0,0 +1,50 @@
from __future__ import annotations
import os
import uuid
import pytest
try:
caldav_args = {
# Those credentials are configured through the Travis UI
"username": os.environ["DAVICAL_USERNAME"].strip(),
"password": os.environ["DAVICAL_PASSWORD"].strip(),
"url": "https://brutus.lostpackets.de/davical-test/caldav.php/",
}
except KeyError as e:
pytestmark = pytest.mark.skip(f"Missing envkey: {e!s}")
@pytest.mark.flaky(reruns=5)
class ServerMixin:
@pytest.fixture
def davical_args(self):
if self.storage_class.fileext == ".ics":
return dict(caldav_args)
elif self.storage_class.fileext == ".vcf":
pytest.skip("No carddav")
else:
raise RuntimeError
@pytest.fixture
def get_storage_args(self, davical_args, request):
async def inner(collection="test"):
if collection is None:
return davical_args
assert collection.startswith("test")
for _ in range(4):
args = self.storage_class.create_collection(
collection + str(uuid.uuid4()), **davical_args
)
s = self.storage_class(**args)
if not list(s.list()):
# See: https://stackoverflow.com/a/33984811
request.addfinalizer(lambda x=s: x.session.request("DELETE", ""))
return args
raise RuntimeError("Failed to find free collection.")
return inner

View file

@ -0,0 +1 @@
pip install pytest-rerunfailures

View file

@ -0,0 +1,42 @@
from __future__ import annotations
import os
import pytest
class ServerMixin:
@pytest.fixture
def get_storage_args(self, slow_create_collection, aio_connector, request):
if (
"item_type" in request.fixturenames
and request.getfixturevalue("item_type") == "VTODO"
):
# Fastmail has non-standard support for TODOs
# See https://github.com/pimutils/vdirsyncer/issues/824
pytest.skip("Fastmail has non-standard VTODO support.")
async def inner(collection="test"):
args = {
"username": os.environ["FASTMAIL_USERNAME"],
"password": os.environ["FASTMAIL_PASSWORD"],
"connector": aio_connector,
}
if self.storage_class.fileext == ".ics":
args["url"] = "https://caldav.fastmail.com/"
elif self.storage_class.fileext == ".vcf":
args["url"] = "https://carddav.fastmail.com/"
else:
raise RuntimeError
if collection is not None:
args = await slow_create_collection(
self.storage_class,
args,
collection,
)
return args
return inner

View file

@ -0,0 +1,33 @@
from __future__ import annotations
import os
import pytest
class ServerMixin:
@pytest.fixture
def get_storage_args(self, item_type, slow_create_collection):
if item_type != "VEVENT":
# iCloud collections can either be calendars or task lists.
# See https://github.com/pimutils/vdirsyncer/pull/593#issuecomment-285941615
pytest.skip("iCloud doesn't support anything else than VEVENT")
async def inner(collection="test"):
args = {
"username": os.environ["ICLOUD_USERNAME"],
"password": os.environ["ICLOUD_PASSWORD"],
}
if self.storage_class.fileext == ".ics":
args["url"] = "https://caldav.icloud.com/"
elif self.storage_class.fileext == ".vcf":
args["url"] = "https://contacts.icloud.com/"
else:
raise RuntimeError
if collection is not None:
args = slow_create_collection(self.storage_class, args, collection)
return args
return inner

View file

@ -0,0 +1,33 @@
from __future__ import annotations
import pytest
class ServerMixin:
@pytest.fixture
def get_storage_args(
self,
request,
tmpdir,
slow_create_collection,
radicale_server,
aio_connector,
):
async def inner(collection="test"):
url = "http://127.0.0.1:8001/"
args = {
"url": url,
"username": "radicale",
"password": "radicale",
"connector": aio_connector,
}
if collection is not None:
args = await slow_create_collection(
self.storage_class,
args,
collection,
)
return args
return inner

View file

@ -0,0 +1,9 @@
from __future__ import annotations
import pytest
class ServerMixin:
@pytest.fixture
def get_storage_args(self):
pytest.skip("DAV tests disabled.")

View file

@ -0,0 +1,29 @@
from __future__ import annotations
import pytest
class ServerMixin:
@pytest.fixture
def get_storage_args(
self,
request,
tmpdir,
slow_create_collection,
xandikos_server,
aio_connector,
):
async def inner(collection="test"):
url = "http://127.0.0.1:8000/"
args = {"url": url, "connector": aio_connector}
if collection is not None:
args = await slow_create_collection(
self.storage_class,
args,
collection,
)
return args
return inner

View file

@ -1,18 +1,12 @@
from __future__ import annotations
# -*- coding: utf-8 -*- import subprocess
'''
tests.storage.filesystem
~~~~~~~~~~~~~~~~~~~~~~~~
:copyright: (c) 2014 Markus Unterwaditzer & contributors
:license: MIT, see LICENSE for more details.
'''
import os
import aiostream
import pytest import pytest
from vdirsyncer.storage.filesystem import FilesystemStorage from vdirsyncer.storage.filesystem import FilesystemStorage
from vdirsyncer.vobject import Item
from . import StorageTests from . import StorageTests
@ -20,38 +14,119 @@ from . import StorageTests
class TestFilesystemStorage(StorageTests): class TestFilesystemStorage(StorageTests):
storage_class = FilesystemStorage storage_class = FilesystemStorage
@pytest.fixture(autouse=True) @pytest.fixture
def setup(self, tmpdir): def get_storage_args(self, tmpdir):
self.tmpdir = str(tmpdir) async def inner(collection="test"):
rv = {"path": str(tmpdir), "fileext": ".txt", "collection": collection}
if collection is not None:
rv = await self.storage_class.create_collection(**rv)
return rv
def get_storage_args(self, collection=None): return inner
path = self.tmpdir
if collection is not None:
os.makedirs(os.path.join(path, collection))
return {'path': path, 'fileext': '.txt', 'collection': collection}
def test_create_is_false(self, tmpdir):
with pytest.raises(IOError):
self.storage_class(str(tmpdir), '.txt', collection='lol',
create=False)
def test_is_not_directory(self, tmpdir): def test_is_not_directory(self, tmpdir):
with pytest.raises(IOError): with pytest.raises(OSError):
f = tmpdir.join('hue') f = tmpdir.join("hue")
f.write('stub') f.write("stub")
self.storage_class(str(tmpdir), '.txt', collection='hue') self.storage_class(str(tmpdir) + "/hue", ".txt")
def test_create_is_true(self, tmpdir): @pytest.mark.asyncio
self.storage_class(str(tmpdir), '.txt', collection='asd') async def test_broken_data(self, tmpdir):
assert tmpdir.listdir() == [tmpdir.join('asd')] s = self.storage_class(str(tmpdir), ".txt")
def test_broken_data(self, tmpdir): class BrokenItem:
s = self.storage_class(str(tmpdir), '.txt') raw = "Ц, Ш, Л, ж, Д, З, Ю".encode()
uid = "jeezus"
class BrokenItem(object):
raw = u'Ц, Ш, Л, ж, Д, З, Ю'.encode('utf-8')
uid = 'jeezus'
ident = uid ident = uid
with pytest.raises(TypeError): with pytest.raises(TypeError):
s.upload(BrokenItem) await s.upload(BrokenItem)
assert not tmpdir.listdir() assert not tmpdir.listdir()
@pytest.mark.asyncio
async def test_ident_with_slash(self, tmpdir):
s = self.storage_class(str(tmpdir), ".txt")
await s.upload(Item("UID:a/b/c"))
(item_file,) = tmpdir.listdir()
assert "/" not in item_file.basename
assert item_file.isfile()
@pytest.mark.asyncio
async def test_ignore_tmp_files(self, tmpdir):
"""Test that files with .tmp suffix beside .ics files are ignored."""
s = self.storage_class(str(tmpdir), ".ics")
await s.upload(Item("UID:xyzxyz"))
(item_file,) = tmpdir.listdir()
item_file.copy(item_file.new(ext="tmp"))
assert len(tmpdir.listdir()) == 2
assert len(await aiostream.stream.list(s.list())) == 1
@pytest.mark.asyncio
async def test_ignore_tmp_files_empty_fileext(self, tmpdir):
"""Test that files with .tmp suffix are ignored with empty fileext."""
s = self.storage_class(str(tmpdir), "")
await s.upload(Item("UID:xyzxyz"))
(item_file,) = tmpdir.listdir()
item_file.copy(item_file.new(ext="tmp"))
assert len(tmpdir.listdir()) == 2
# assert False, tmpdir.listdir() # enable to see the created filename
assert len(await aiostream.stream.list(s.list())) == 1
@pytest.mark.asyncio
async def test_ignore_files_typical_backup(self, tmpdir):
"""Test file-name ignorance with typical backup ending ~."""
ignorext = "~" # without dot
storage = self.storage_class(str(tmpdir), "", fileignoreext=ignorext)
await storage.upload(Item("UID:xyzxyz"))
(item_file,) = tmpdir.listdir()
item_file.copy(item_file.new(basename=item_file.basename + ignorext))
assert len(tmpdir.listdir()) == 2
assert len(await aiostream.stream.list(storage.list())) == 1
@pytest.mark.asyncio
async def test_too_long_uid(self, tmpdir):
storage = self.storage_class(str(tmpdir), ".txt")
item = Item("UID:" + "hue" * 600)
href, _etag = await storage.upload(item)
assert item.uid not in href
@pytest.mark.asyncio
async def test_post_hook_inactive(self, tmpdir, monkeypatch):
def check_call_mock(*args, **kwargs):
raise AssertionError
monkeypatch.setattr(subprocess, "call", check_call_mock)
s = self.storage_class(str(tmpdir), ".txt", post_hook=None)
await s.upload(Item("UID:a/b/c"))
@pytest.mark.asyncio
async def test_post_hook_active(self, tmpdir, monkeypatch):
calls = []
exe = "foo"
def check_call_mock(call, *args, **kwargs):
calls.append(True)
assert len(call) == 2
assert call[0] == exe
monkeypatch.setattr(subprocess, "call", check_call_mock)
s = self.storage_class(str(tmpdir), ".txt", post_hook=exe)
await s.upload(Item("UID:a/b/c"))
assert calls
@pytest.mark.asyncio
async def test_ignore_git_dirs(self, tmpdir):
tmpdir.mkdir(".git").mkdir("foo")
tmpdir.mkdir("a")
tmpdir.mkdir("b")
expected = {"a", "b"}
actual = {
c["collection"] async for c in self.storage_class.discover(str(tmpdir))
}
assert actual == expected

View file

@ -1,86 +1,163 @@
# -*- coding: utf-8 -*- from __future__ import annotations
'''
tests.storage.test_http
~~~~~~~~~~~~~~~~~~~~~~~
:copyright: (c) 2014 Markus Unterwaditzer & contributors
:license: MIT, see LICENSE for more details.
'''
import aiohttp
import pytest import pytest
from aioresponses import CallbackResult
from requests import Response from aioresponses import aioresponses
from tests import normalize_item from tests import normalize_item
from vdirsyncer.exceptions import UserError
from vdirsyncer.http import BasicAuthMethod
from vdirsyncer.http import DigestAuthMethod
from vdirsyncer.http import UsageLimitReached
from vdirsyncer.http import request
from vdirsyncer.storage.http import HttpStorage from vdirsyncer.storage.http import HttpStorage
from vdirsyncer.storage.http import prepare_auth
def test_list(monkeypatch): @pytest.mark.asyncio
collection_url = 'http://127.0.0.1/calendar/collection.ics' async def test_list(aio_connector):
collection_url = "http://127.0.0.1/calendar/collection.ics"
items = [ items = [
(u'BEGIN:VEVENT\n' (
u'SUMMARY:Eine Kurzinfo\n' "BEGIN:VEVENT\n"
u'DESCRIPTION:Beschreibung des Termines\n' "SUMMARY:Eine Kurzinfo\n"
u'END:VEVENT'), "DESCRIPTION:Beschreibung des Termines\n"
(u'BEGIN:VEVENT\n' "END:VEVENT"
u'SUMMARY:Eine zweite Küèrzinfo\n' ),
u'DESCRIPTION:Beschreibung des anderen Termines\n' (
u'BEGIN:VALARM\n' "BEGIN:VEVENT\n"
u'ACTION:AUDIO\n' "SUMMARY:Eine zweite Küèrzinfo\n"
u'TRIGGER:19980403T120000\n' "DESCRIPTION:Beschreibung des anderen Termines\n"
u'ATTACH;FMTTYPE=audio/basic:http://host.com/pub/ssbanner.aud\n' "BEGIN:VALARM\n"
u'REPEAT:4\n' "ACTION:AUDIO\n"
u'DURATION:PT1H\n' "TRIGGER:19980403T120000\n"
u'END:VALARM\n' "ATTACH;FMTTYPE=audio/basic:http://host.com/pub/ssbanner.aud\n"
u'END:VEVENT') "REPEAT:4\n"
"DURATION:PT1H\n"
"END:VALARM\n"
"END:VEVENT"
),
] ]
responses = [ responses = ["\n".join(["BEGIN:VCALENDAR", *items, "END:VCALENDAR"])] * 2
u'\n'.join([u'BEGIN:VCALENDAR'] + items + [u'END:VCALENDAR'])
] * 2
def get(method, url, *a, **kw): def callback(url, headers, **kwargs):
assert method == 'GET' assert headers["User-Agent"].startswith("vdirsyncer/")
assert url == collection_url
r = Response()
r.status_code = 200
assert responses assert responses
r._content = responses.pop().encode('utf-8')
r.headers['Content-Type'] = 'text/icalendar'
r.encoding = 'ISO-8859-1'
return r
monkeypatch.setattr('requests.request', get) return CallbackResult(
status=200,
body=responses.pop().encode("utf-8"),
headers={"Content-Type": "text/calendar; charset=iso-8859-1"},
)
s = HttpStorage(url=collection_url) with aioresponses() as m:
m.get(collection_url, callback=callback, repeat=True)
found_items = {} s = HttpStorage(url=collection_url, connector=aio_connector)
for href, etag in s.list(): found_items = {}
item, etag2 = s.get(href)
assert item.uid is None
assert etag2 == etag
found_items[normalize_item(item)] = href
expected = set(normalize_item(u'BEGIN:VCALENDAR\n' + x + '\nEND:VCALENDAR') async for href, etag in s.list():
for x in items) item, etag2 = await s.get(href)
assert item.uid is not None
assert etag2 == etag
found_items[normalize_item(item)] = href
assert set(found_items) == expected expected = {
normalize_item("BEGIN:VCALENDAR\n" + x + "\nEND:VCALENDAR") for x in items
}
for href, etag in s.list(): assert set(found_items) == expected
item, etag2 = s.get(href)
assert item.uid is None async for href, etag in s.list():
assert etag2 == etag item, etag2 = await s.get(href)
assert found_items[normalize_item(item)] == href assert item.uid is not None
assert etag2 == etag
assert found_items[normalize_item(item)] == href
def test_readonly_param(): def test_readonly_param(aio_connector):
url = u'http://example.com/' """The ``readonly`` param cannot be ``False``."""
url = "http://example.com/"
with pytest.raises(ValueError): with pytest.raises(ValueError):
HttpStorage(url=url, read_only=False) HttpStorage(url=url, read_only=False, connector=aio_connector)
a = HttpStorage(url=url, read_only=True).read_only a = HttpStorage(url=url, read_only=True, connector=aio_connector)
b = HttpStorage(url=url, read_only=None).read_only b = HttpStorage(url=url, read_only=None, connector=aio_connector)
assert a is b is True
assert a.read_only is b.read_only is True
def test_prepare_auth():
assert prepare_auth(None, "", "") is None
assert prepare_auth(None, "user", "pwd") == BasicAuthMethod("user", "pwd")
assert prepare_auth("basic", "user", "pwd") == BasicAuthMethod("user", "pwd")
with pytest.raises(ValueError) as excinfo:
assert prepare_auth("basic", "", "pwd")
assert "you need to specify username and password" in str(excinfo.value).lower()
assert isinstance(prepare_auth("digest", "user", "pwd"), DigestAuthMethod)
with pytest.raises(ValueError) as excinfo:
prepare_auth("ladida", "user", "pwd")
assert "unknown authentication method" in str(excinfo.value).lower()
def test_prepare_auth_guess():
# guess auth is currently not supported
with pytest.raises(UserError) as excinfo:
prepare_auth("guess", "usr", "pwd")
assert "not supported" in str(excinfo.value).lower()
def test_verify_false_disallowed(aio_connector):
with pytest.raises(ValueError) as excinfo:
HttpStorage(url="http://example.com", verify=False, connector=aio_connector)
assert "must be a path to a pem-file." in str(excinfo.value).lower()
@pytest.mark.asyncio
async def test_403_usage_limit_exceeded(aio_connector):
url = "http://127.0.0.1/test_403"
error_body = {
"error": {
"errors": [
{
"domain": "usageLimits",
"message": "Calendar usage limits exceeded.",
"reason": "quotaExceeded",
}
],
"code": 403,
"message": "Calendar usage limits exceeded.",
}
}
async with aiohttp.ClientSession(connector=aio_connector) as session:
with aioresponses() as m:
m.get(url, status=403, payload=error_body, repeat=True)
with pytest.raises(UsageLimitReached):
await request("GET", url, session)
@pytest.mark.asyncio
async def test_403_without_usage_limits_domain(aio_connector):
"""A 403 JSON error without the Google 'usageLimits' domain should not be
treated as UsageLimitReached and should surface as ClientResponseError.
"""
url = "http://127.0.0.1/test_403_no_usage_limits"
async with aiohttp.ClientSession(connector=aio_connector) as session:
with aioresponses() as m:
m.get(url, status=403, repeat=True)
with pytest.raises(aiohttp.ClientResponseError):
await request("GET", url, session)

View file

@ -1,93 +1,93 @@
# -*- coding: utf-8 -*- from __future__ import annotations
'''
tests.storage.test_http_with_singlefile
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
:copyright: (c) 2014 Markus Unterwaditzer & contributors
:license: MIT, see LICENSE for more details.
'''
import aiostream
import pytest import pytest
from aioresponses import CallbackResult
from aioresponses import aioresponses
from requests import Response
from vdirsyncer.storage.base import Storage
import vdirsyncer.storage.http import vdirsyncer.storage.http
from vdirsyncer.storage.base import Storage
from vdirsyncer.storage.singlefile import SingleFileStorage from vdirsyncer.storage.singlefile import SingleFileStorage
from . import BaseStorageTests from . import StorageTests
from .. import EVENT_TEMPLATE, assert_item_equals
class CombinedStorage(Storage): class CombinedStorage(Storage):
'''A subclass of HttpStorage to make testing easier. It supports writes via """A subclass of HttpStorage to make testing easier. It supports writes via
SingleFileStorage.''' SingleFileStorage."""
_repr_attributes = ('url', 'path')
def __init__(self, url, path, **kwargs): _repr_attributes = ("url", "path")
super(CombinedStorage, self).__init__(**kwargs) storage_name = "http_and_singlefile"
def __init__(self, url, path, *, connector, **kwargs):
if kwargs.get("collection") is not None:
raise ValueError
super().__init__(**kwargs)
self.url = url self.url = url
self.path = path self.path = path
self._reader = vdirsyncer.storage.http.HttpStorage(url=url) self._reader = vdirsyncer.storage.http.HttpStorage(url=url, connector=connector)
self._reader._ignore_uids = False
self._writer = SingleFileStorage(path=path) self._writer = SingleFileStorage(path=path)
def list(self, *a, **kw): async def list(self, *a, **kw):
return self._reader.list(*a, **kw) async for item in self._reader.list(*a, **kw):
yield item
def get(self, *a, **kw): async def get(self, *a, **kw):
self.list() await aiostream.stream.list(self.list())
return self._reader.get(*a, **kw) return await self._reader.get(*a, **kw)
def upload(self, *a, **kw): async def upload(self, *a, **kw):
return self._writer.upload(*a, **kw) return await self._writer.upload(*a, **kw)
def update(self, *a, **kw): async def update(self, *a, **kw):
return self._writer.update(*a, **kw) return await self._writer.update(*a, **kw)
def delete(self, *a, **kw): async def delete(self, *a, **kw):
return self._writer.delete(*a, **kw) return await self._writer.delete(*a, **kw)
class TestHttpStorage(BaseStorageTests): class TestHttpStorage(StorageTests):
storage_class = CombinedStorage storage_class = CombinedStorage
item_template = EVENT_TEMPLATE supports_collections = False
supports_metadata = False
@pytest.fixture(autouse=True) @pytest.fixture(autouse=True)
def setup_tmpdir(self, tmpdir, monkeypatch): def setup_tmpdir(self, tmpdir, monkeypatch):
self.tmpfile = str(tmpdir.join('collection.txt')) self.tmpfile = str(tmpdir.ensure("collection.txt"))
def _request(method, url, *args, **kwargs): def callback(url, headers, **kwargs):
assert method == 'GET' """Read our tmpfile at request time.
assert url == 'http://localhost:123/collection.txt'
r = Response()
r.status_code = 200
try:
with open(self.tmpfile, 'rb') as f:
r._content = f.read()
except IOError:
r._content = b''
r.headers['Content-Type'] = 'text/icalendar' We can't just read this during test setup since the file get written to
r.encoding = 'ISO-8859-1' during test execution.
return r
monkeypatch.setattr(vdirsyncer.storage.http, 'request', _request) It might make sense to actually run a server serving the local file.
"""
assert headers["User-Agent"].startswith("vdirsyncer/")
def get_storage_args(self, collection=None): with open(self.tmpfile) as f:
assert collection is None body = f.read()
return {'url': 'http://localhost:123/collection.txt',
'path': self.tmpfile}
def test_update(self, s): return CallbackResult(
'''The original testcase tries to fetch with the old href. But this status=200,
storage doesn't have real hrefs, so the href might change if the body=body,
underlying UID changes. ''' headers={"Content-Type": "text/calendar; charset=utf-8"},
)
item = self._create_bogus_item() with aioresponses() as m:
href, etag = s.upload(item) m.get("http://localhost:123/collection.txt", callback=callback, repeat=True)
assert_item_equals(s.get(href)[0], item) yield
new_item = self._create_bogus_item() @pytest.fixture
s.update(href, new_item, etag) def get_storage_args(self, aio_connector):
((new_href, new_etag),) = s.list() async def inner(collection=None):
assert_item_equals(s.get(new_href)[0], new_item) assert collection is None
return {
"url": "http://localhost:123/collection.txt",
"path": self.tmpfile,
"connector": aio_connector,
}
return inner

View file

@ -1,21 +1,19 @@
from __future__ import annotations
# -*- coding: utf-8 -*- import pytest
'''
tests.storage.test_memory
~~~~~~~~~~~~~~~~~~~~~~~~~
:copyright: (c) 2014 Markus Unterwaditzer & contributors
:license: MIT, see LICENSE for more details.
'''
from vdirsyncer.storage.memory import MemoryStorage from vdirsyncer.storage.memory import MemoryStorage
from . import BaseStorageTests from . import StorageTests
class TestMemoryStorage(BaseStorageTests): class TestMemoryStorage(StorageTests):
storage_class = MemoryStorage storage_class = MemoryStorage
supports_collections = False
def get_storage_args(self, **kwargs): @pytest.fixture
return kwargs def get_storage_args(self):
async def inner(**args):
return args
return inner

View file

@ -1,57 +1,22 @@
# -*- coding: utf-8 -*- from __future__ import annotations
'''
tests.storage.test_singlefile
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
:copyright: (c) 2014 Markus Unterwaditzer & contributors
:license: MIT, see LICENSE for more details.
'''
import pytest import pytest
from vdirsyncer.storage.singlefile import SingleFileStorage from vdirsyncer.storage.singlefile import SingleFileStorage
from . import BaseStorageTests from . import StorageTests
from .. import EVENT_TEMPLATE, assert_item_equals
class TestSingleFileStorage(BaseStorageTests): class TestSingleFileStorage(StorageTests):
storage_class = SingleFileStorage storage_class = SingleFileStorage
item_template = EVENT_TEMPLATE supports_metadata = False
@pytest.fixture(autouse=True) @pytest.fixture
def setup(self, tmpdir): def get_storage_args(self, tmpdir):
self._path = str(tmpdir.join('test.txt')) async def inner(collection="test"):
rv = {"path": str(tmpdir.join("%s.txt")), "collection": collection}
if collection is not None:
rv = await self.storage_class.create_collection(**rv)
return rv
def get_storage_args(self, **kwargs): return inner
return dict(path=self._path)
def test_collection_arg(self, tmpdir):
with pytest.raises(ValueError):
self.storage_class(str(tmpdir.join('foo.ics')), collection='ha')
def test_create_arg(self, tmpdir):
s = self.storage_class(str(tmpdir) + '/foo.ics')
assert not s.list()
s.create = False
with pytest.raises(IOError):
s.list()
with pytest.raises(IOError):
s = self.storage_class(str(tmpdir) + '/foo.ics', create=False)
def test_update(self, s):
'''The original testcase tries to fetch with the old href. But this
storage doesn't have real hrefs, so the href might change if the
underlying UID changes. '''
item = self._create_bogus_item()
href, etag = s.upload(item)
assert_item_equals(s.get(href)[0], item)
new_item = self._create_bogus_item()
s.update(href, new_item, etag)
((new_href, new_etag),) = s.list()
assert_item_equals(s.get(new_href)[0], new_item)

View file

View file

@ -0,0 +1,36 @@
from __future__ import annotations
from textwrap import dedent
import pytest
from click.testing import CliRunner
import vdirsyncer.cli as cli
class _CustomRunner:
def __init__(self, tmpdir):
self.tmpdir = tmpdir
self.cfg = tmpdir.join("config")
self.runner = CliRunner()
def invoke(self, args, env=None, **kwargs):
env = env or {}
env.setdefault("VDIRSYNCER_CONFIG", str(self.cfg))
return self.runner.invoke(cli.app, args, env=env, **kwargs)
def write_with_general(self, data):
self.cfg.write(
dedent(
"""
[general]
status_path = "{}/status/"
"""
).format(str(self.tmpdir))
)
self.cfg.write(data, mode="a")
@pytest.fixture
def runner(tmpdir):
return _CustomRunner(tmpdir)

View file

@ -0,0 +1,283 @@
from __future__ import annotations
import io
from textwrap import dedent
import pytest
from vdirsyncer import cli
from vdirsyncer import exceptions
from vdirsyncer.cli.config import Config
invalid = object()
@pytest.fixture
def read_config(tmpdir, monkeypatch):
def inner(cfg):
errors = []
monkeypatch.setattr("vdirsyncer.cli.cli_logger.error", errors.append)
f = io.StringIO(dedent(cfg.format(base=str(tmpdir))))
rv = Config.from_fileobject(f)
monkeypatch.undo()
return errors, rv
return inner
def test_read_config(read_config):
_errors, c = read_config(
"""
[general]
status_path = "/tmp/status/"
[pair bob]
a = "bob_a"
b = "bob_b"
collections = null
[storage bob_a]
type = "filesystem"
path = "/tmp/contacts/"
fileext = ".vcf"
yesno = false
number = 42
[storage bob_b]
type = "carddav"
"""
)
assert c.general == {"status_path": "/tmp/status/"}
assert set(c.pairs) == {"bob"}
bob = c.pairs["bob"]
assert bob.collections is None
assert c.storages == {
"bob_a": {
"type": "filesystem",
"path": "/tmp/contacts/",
"fileext": ".vcf",
"yesno": False,
"number": 42,
"instance_name": "bob_a",
},
"bob_b": {"type": "carddav", "instance_name": "bob_b"},
}
def test_missing_collections_param(read_config):
with pytest.raises(exceptions.UserError) as excinfo:
read_config(
"""
[general]
status_path = "/tmp/status/"
[pair bob]
a = "bob_a"
b = "bob_b"
[storage bob_a]
type = "lmao"
[storage bob_b]
type = "lmao"
"""
)
assert "collections parameter missing" in str(excinfo.value)
def test_invalid_section_type(read_config):
with pytest.raises(exceptions.UserError) as excinfo:
read_config(
"""
[general]
status_path = "/tmp/status/"
[bogus]
"""
)
assert "Unknown section" in str(excinfo.value)
assert "bogus" in str(excinfo.value)
def test_missing_general_section(read_config):
with pytest.raises(exceptions.UserError) as excinfo:
read_config(
"""
[pair my_pair]
a = "my_a"
b = "my_b"
collections = null
[storage my_a]
type = "filesystem"
path = "{base}/path_a/"
fileext = ".txt"
[storage my_b]
type = "filesystem"
path = "{base}/path_b/"
fileext = ".txt"
"""
)
assert "Invalid general section." in str(excinfo.value)
def test_wrong_general_section(read_config):
with pytest.raises(exceptions.UserError) as excinfo:
read_config(
"""
[general]
wrong = true
"""
)
assert "Invalid general section." in str(excinfo.value)
assert excinfo.value.problems == [
"general section doesn't take the parameters: wrong",
"general section is missing the parameters: status_path",
]
def test_invalid_storage_name(read_config):
with pytest.raises(exceptions.UserError) as excinfo:
read_config(
"""
[general]
status_path = "{base}/status/"
[storage foo.bar]
"""
)
assert "invalid characters" in str(excinfo.value).lower()
def test_invalid_collections_arg(read_config):
with pytest.raises(exceptions.UserError) as excinfo:
read_config(
"""
[general]
status_path = "/tmp/status/"
[pair foobar]
a = "foo"
b = "bar"
collections = [null]
[storage foo]
type = "filesystem"
path = "/tmp/foo/"
fileext = ".txt"
[storage bar]
type = "filesystem"
path = "/tmp/bar/"
fileext = ".txt"
"""
)
assert "Expected string" in str(excinfo.value)
def test_duplicate_sections(read_config):
with pytest.raises(exceptions.UserError) as excinfo:
read_config(
"""
[general]
status_path = "/tmp/status/"
[pair foobar]
a = "foobar"
b = "bar"
collections = null
[storage foobar]
type = "filesystem"
path = "/tmp/foo/"
fileext = ".txt"
[storage bar]
type = "filesystem"
path = "/tmp/bar/"
fileext = ".txt"
"""
)
assert 'Name "foobar" already used' in str(excinfo.value)
def test_validate_collections_param():
x = cli.config._validate_collections_param
x(None)
x(["c", "a", "b"])
pytest.raises(ValueError, x, [None])
pytest.raises(ValueError, x, ["a", "a", "a"])
pytest.raises(ValueError, x, [[None, "a", "b"]])
x([["c", None, "b"]])
x([["c", "a", None]])
x([["c", None, None]])
def test_invalid_implicit_value(read_config):
expected_message = "`implicit` parameter must be 'create' or absent"
with pytest.raises(exceptions.UserError) as excinfo:
read_config(
"""
[general]
status_path = "/tmp/status/"
[pair my_pair]
a = "my_a"
b = "my_b"
collections = null
implicit = "invalid"
[storage my_a]
type = "filesystem"
path = "{base}/path_a/"
fileext = ".txt"
[storage my_b]
type = "filesystem"
path = "{base}/path_b/"
fileext = ".txt"
"""
)
assert expected_message in str(excinfo.value)
def test_implicit_create_only(read_config):
"""Test that implicit create works."""
errors, c = read_config(
"""
[general]
status_path = "/tmp/status/"
[pair my_pair]
a = "my_a"
b = "my_b"
collections = ["from a", "from b"]
implicit = "create"
[storage my_a]
type = "filesystem"
path = "{base}/path_a/"
fileext = ".txt"
[storage my_b]
type = "filesystem"
path = "{base}/path_b/"
fileext = ".txt"
"""
)
assert not errors
pair = c.pairs["my_pair"]
assert pair.implicit == "create"

View file

@ -0,0 +1,287 @@
from __future__ import annotations
import json
from textwrap import dedent
import pytest
from vdirsyncer import exceptions
from vdirsyncer.storage.base import Storage
def test_discover_command(tmpdir, runner):
runner.write_with_general(
dedent(
"""
[storage foo]
type = "filesystem"
path = "{0}/foo/"
fileext = ".txt"
[storage bar]
type = "filesystem"
path = "{0}/bar/"
fileext = ".txt"
[pair foobar]
a = "foo"
b = "bar"
collections = ["from a"]
"""
).format(str(tmpdir))
)
foo = tmpdir.mkdir("foo")
bar = tmpdir.mkdir("bar")
for x in "abc":
foo.mkdir(x)
bar.mkdir(x)
bar.mkdir("d")
result = runner.invoke(["discover"])
assert not result.exception
foo.mkdir("d")
result = runner.invoke(["sync"])
assert not result.exception
lines = result.output.splitlines()
assert "Syncing foobar/a" in lines
assert "Syncing foobar/b" in lines
assert "Syncing foobar/c" in lines
assert "Syncing foobar/d" not in result.output
result = runner.invoke(["discover"])
assert not result.exception
result = runner.invoke(["sync"])
assert not result.exception
assert "Syncing foobar/a" in lines
assert "Syncing foobar/b" in lines
assert "Syncing foobar/c" in lines
assert "Syncing foobar/d" in result.output
# Check for redundant data that is already in the config. This avoids
# copying passwords from the config too.
assert "fileext" not in tmpdir.join("status").join("foobar.collections").read()
def test_discover_different_collection_names(tmpdir, runner):
foo = tmpdir.mkdir("foo")
bar = tmpdir.mkdir("bar")
runner.write_with_general(
dedent(
"""
[storage foo]
type = "filesystem"
fileext = ".txt"
path = "{foo}"
[storage bar]
type = "filesystem"
fileext = ".txt"
path = "{bar}"
[pair foobar]
a = "foo"
b = "bar"
collections = [
["coll1", "coll_a1", "coll_b1"],
"coll2"
]
"""
).format(foo=str(foo), bar=str(bar))
)
result = runner.invoke(["discover"], input="y\n" * 6)
assert not result.exception
coll_a1 = foo.join("coll_a1")
coll_b1 = bar.join("coll_b1")
assert coll_a1.exists()
assert coll_b1.exists()
result = runner.invoke(["sync"])
assert not result.exception
foo_txt = coll_a1.join("foo.txt")
foo_txt.write("BEGIN:VCALENDAR\nUID:foo\nEND:VCALENDAR")
result = runner.invoke(["sync"])
assert not result.exception
assert foo_txt.exists()
assert coll_b1.join("foo.txt").exists()
def test_discover_direct_path(tmpdir, runner):
foo = tmpdir.join("foo")
bar = tmpdir.join("bar")
runner.write_with_general(
dedent(
"""
[storage foo]
type = "filesystem"
fileext = ".txt"
path = "{foo}"
[storage bar]
type = "filesystem"
fileext = ".txt"
path = "{bar}"
[pair foobar]
a = "foo"
b = "bar"
collections = null
"""
).format(foo=str(foo), bar=str(bar))
)
result = runner.invoke(["discover"], input="y\n" * 2)
assert not result.exception
result = runner.invoke(["sync"])
assert not result.exception
assert foo.exists()
assert bar.exists()
def test_null_collection_with_named_collection(tmpdir, runner):
runner.write_with_general(
dedent(
f"""
[pair foobar]
a = "foo"
b = "bar"
collections = [["baz", "baz", null]]
[storage foo]
type = "filesystem"
path = "{tmpdir!s}/foo/"
fileext = ".txt"
[storage bar]
type = "singlefile"
path = "{tmpdir!s}/bar.txt"
"""
)
)
result = runner.invoke(["discover"], input="y\n" * 2)
assert not result.exception
foo = tmpdir.join("foo")
foobaz = foo.join("baz")
assert foo.exists()
assert foobaz.exists()
bar = tmpdir.join("bar.txt")
assert bar.exists()
foobaz.join("lol.txt").write("BEGIN:VCARD\nUID:HAHA\nEND:VCARD")
result = runner.invoke(["sync"])
assert not result.exception
assert "HAHA" in bar.read()
@pytest.mark.parametrize(
("a_requires", "b_requires"),
[
(True, True),
(True, False),
(False, True),
(False, False),
],
)
def test_collection_required(a_requires, b_requires, tmpdir, runner, monkeypatch):
class TestStorage(Storage):
storage_name = "test"
def __init__(self, require_collection, **kw):
if require_collection:
assert not kw.get("collection")
raise exceptions.CollectionRequired
async def get(self, href: str):
raise NotImplementedError
async def list(self) -> list[tuple]:
raise NotImplementedError
from vdirsyncer.cli.utils import storage_names
monkeypatch.setitem(storage_names._storages, "test", TestStorage)
runner.write_with_general(
dedent(
f"""
[pair foobar]
a = "foo"
b = "bar"
collections = null
[storage foo]
type = "test"
require_collection = {json.dumps(a_requires)}
[storage bar]
type = "test"
require_collection = {json.dumps(b_requires)}
"""
)
)
result = runner.invoke(["discover"])
if a_requires or b_requires:
assert result.exception
assert (
"One or more storages don't support `collections = null`." in result.output
)
def test_showconfig(tmpdir, runner):
runner.write_with_general(
dedent(
"""
[storage foo]
type = "filesystem"
path = "{0}/foo/"
fileext = ".txt"
[storage bar]
type = "filesystem"
path = "{0}/bar/"
fileext = ".txt"
[pair foobar]
a = "foo"
b = "bar"
collections = ["from a"]
"""
).format(str(tmpdir))
)
result = runner.invoke(["showconfig"])
assert not result.exception
assert json.loads(result.output) == {
"storages": [
{
"type": "filesystem",
"path": f"{tmpdir}/foo/",
"fileext": ".txt",
"instance_name": "foo",
},
{
"type": "filesystem",
"path": f"{tmpdir}/bar/",
"fileext": ".txt",
"instance_name": "bar",
},
]
}

View file

@ -0,0 +1,48 @@
from __future__ import annotations
from textwrap import dedent
def test_get_password_from_command(tmpdir, runner):
runner.write_with_general(
dedent(
f"""
[pair foobar]
a = "foo"
b = "bar"
collections = ["a", "b", "c"]
[storage foo]
type.fetch = ["shell", "echo filesystem"]
path = "{tmpdir!s}/foo/"
fileext.fetch = ["command", "echo", ".txt"]
[storage bar]
type = "filesystem"
path = "{tmpdir!s}/bar/"
fileext.fetch = ["prompt", "Fileext for bar"]
"""
)
)
foo = tmpdir.ensure("foo", dir=True)
foo.ensure("a", dir=True)
foo.ensure("b", dir=True)
foo.ensure("c", dir=True)
bar = tmpdir.ensure("bar", dir=True)
bar.ensure("a", dir=True)
bar.ensure("b", dir=True)
bar.ensure("c", dir=True)
result = runner.invoke(["discover"], input=".asdf\n")
assert not result.exception
status = tmpdir.join("status").join("foobar.collections").read()
assert "foo" in status
assert "bar" in status
assert "asdf" not in status
assert "txt" not in status
foo.join("a").join("foo.txt").write("BEGIN:VCARD\nUID:foo\nEND:VCARD")
result = runner.invoke(["sync"], input=".asdf\n")
assert not result.exception
assert [x.basename for x in bar.join("a").listdir()] == ["foo.asdf"]

View file

@ -0,0 +1,78 @@
from __future__ import annotations
from textwrap import dedent
import pytest
@pytest.fixture
def storage(tmpdir, runner):
runner.write_with_general(
dedent(
"""
[storage foo]
type = "filesystem"
path = "{base}/foo/"
fileext = ".txt"
"""
).format(base=str(tmpdir))
)
return tmpdir.mkdir("foo")
@pytest.mark.parametrize("collection", [None, "foocoll"])
def test_basic(storage, runner, collection):
if collection is not None:
storage = storage.mkdir(collection)
collection_arg = f"foo/{collection}"
else:
collection_arg = "foo"
argv = ["repair", collection_arg]
result = runner.invoke(argv, input="y")
assert not result.exception
storage.join("item.txt").write("BEGIN:VCARD\nEND:VCARD")
storage.join("toobroken.txt").write("")
result = runner.invoke(argv, input="y")
assert not result.exception
assert "No UID" in result.output
assert "'toobroken.txt' is malformed beyond repair" in result.output
(new_fname,) = (x for x in storage.listdir() if "toobroken" not in str(x))
assert "UID:" in new_fname.read()
@pytest.mark.parametrize("repair_uids", [None, True, False])
def test_repair_uids(storage, runner, repair_uids):
f = storage.join("baduid.txt")
orig_f = "BEGIN:VCARD\nUID:!!!!!\nEND:VCARD"
f.write(orig_f)
if repair_uids is None:
opt = []
elif repair_uids:
opt = ["--repair-unsafe-uid"]
else:
opt = ["--no-repair-unsafe-uid"]
result = runner.invoke(["repair", *opt, "foo"], input="y")
assert not result.exception
if repair_uids:
assert "UID or href is unsafe, assigning random UID" in result.output
assert not f.exists()
(new_f,) = storage.listdir()
s = new_f.read()
assert s.startswith("BEGIN:VCARD")
assert s.endswith("END:VCARD")
assert s != orig_f
else:
assert (
"UID may cause problems, add --repair-unsafe-uid to repair."
in result.output
)
assert f.read() == orig_f

View file

@ -0,0 +1,579 @@
from __future__ import annotations
import json
import sys
from textwrap import dedent
import pytest
def test_simple_run(tmpdir, runner):
runner.write_with_general(
dedent(
"""
[pair my_pair]
a = "my_a"
b = "my_b"
collections = null
[storage my_a]
type = "filesystem"
path = "{0}/path_a/"
fileext = ".txt"
[storage my_b]
type = "filesystem"
path = "{0}/path_b/"
fileext = ".txt"
"""
).format(str(tmpdir))
)
tmpdir.mkdir("path_a")
tmpdir.mkdir("path_b")
result = runner.invoke(["discover"])
assert not result.exception
result = runner.invoke(["sync"])
assert not result.exception
tmpdir.join("path_a/haha.txt").write("UID:haha")
result = runner.invoke(["sync"])
assert "Copying (uploading) item haha to my_b" in result.output
assert tmpdir.join("path_b/haha.txt").read() == "UID:haha"
def test_sync_inexistant_pair(tmpdir, runner):
runner.write_with_general("")
result = runner.invoke(["sync", "foo"])
assert result.exception
assert "pair foo does not exist." in result.output.lower()
def test_empty_storage(tmpdir, runner):
runner.write_with_general(
dedent(
"""
[pair my_pair]
a = "my_a"
b = "my_b"
collections = null
[storage my_a]
type = "filesystem"
path = "{0}/path_a/"
fileext = ".txt"
[storage my_b]
type = "filesystem"
path = "{0}/path_b/"
fileext = ".txt"
"""
).format(str(tmpdir))
)
tmpdir.mkdir("path_a")
tmpdir.mkdir("path_b")
result = runner.invoke(["discover"])
assert not result.exception
result = runner.invoke(["sync"])
assert not result.exception
tmpdir.join("path_a/haha.txt").write("UID:haha")
result = runner.invoke(["sync"])
assert not result.exception
tmpdir.join("path_b/haha.txt").remove()
result = runner.invoke(["sync"])
lines = result.output.splitlines()
assert lines[0] == "Syncing my_pair"
assert lines[1].startswith('error: my_pair: Storage "my_b" was completely emptied.')
assert result.exception
def test_verbosity(tmpdir, runner):
runner.write_with_general("")
result = runner.invoke(["--verbosity=HAHA", "sync"])
assert result.exception
assert (
'invalid value for "--verbosity"' in result.output.lower()
or "invalid value for '--verbosity'" in result.output.lower()
)
def test_collections_cache_invalidation(tmpdir, runner):
foo = tmpdir.mkdir("foo")
bar = tmpdir.mkdir("bar")
for x in "abc":
foo.mkdir(x)
bar.mkdir(x)
runner.write_with_general(
dedent(
"""
[storage foo]
type = "filesystem"
path = "{0}/foo/"
fileext = ".txt"
[storage bar]
type = "filesystem"
path = "{0}/bar/"
fileext = ".txt"
[pair foobar]
a = "foo"
b = "bar"
collections = ["a", "b", "c"]
"""
).format(str(tmpdir))
)
foo.join("a/itemone.txt").write("UID:itemone")
result = runner.invoke(["discover"])
assert not result.exception
result = runner.invoke(["sync"])
assert not result.exception
assert "detected change in config file" not in result.output.lower()
rv = bar.join("a").listdir()
assert len(rv) == 1
assert rv[0].basename == "itemone.txt"
runner.write_with_general(
dedent(
"""
[storage foo]
type = "filesystem"
path = "{0}/foo/"
fileext = ".txt"
[storage bar]
type = "filesystem"
path = "{0}/bar2/"
fileext = ".txt"
[pair foobar]
a = "foo"
b = "bar"
collections = ["a", "b", "c"]
"""
).format(str(tmpdir))
)
for entry in tmpdir.join("status").listdir():
if not str(entry).endswith(".collections"):
entry.remove()
bar2 = tmpdir.mkdir("bar2")
for x in "abc":
bar2.mkdir(x)
result = runner.invoke(["sync"])
assert "detected change in config file" in result.output.lower()
assert result.exception
result = runner.invoke(["discover"])
assert not result.exception
result = runner.invoke(["sync"])
assert not result.exception
rv = bar.join("a").listdir()
rv2 = bar2.join("a").listdir()
assert len(rv) == len(rv2) == 1
assert rv[0].basename == rv2[0].basename == "itemone.txt"
def test_invalid_pairs_as_cli_arg(tmpdir, runner):
runner.write_with_general(
dedent(
"""
[storage foo]
type = "filesystem"
path = "{0}/foo/"
fileext = ".txt"
[storage bar]
type = "filesystem"
path = "{0}/bar/"
fileext = ".txt"
[pair foobar]
a = "foo"
b = "bar"
collections = ["a", "b", "c"]
"""
).format(str(tmpdir))
)
for base in ("foo", "bar"):
base = tmpdir.mkdir(base)
for c in "abc":
base.mkdir(c)
result = runner.invoke(["discover"])
assert not result.exception
result = runner.invoke(["sync", "foobar/d"])
assert result.exception
assert 'pair foobar: collection "d" not found' in result.output.lower()
def test_multiple_pairs(tmpdir, runner):
def get_cfg():
for name_a, name_b in ("foo", "bar"), ("bam", "baz"):
yield dedent(
"""
[pair {a}{b}]
a = "{a}"
b = "{b}"
collections = null
"""
).format(a=name_a, b=name_b)
for name in name_a, name_b:
yield dedent(
"""
[storage {name}]
type = "filesystem"
path = "{path}"
fileext = ".txt"
"""
).format(name=name, path=str(tmpdir.mkdir(name)))
runner.write_with_general("".join(get_cfg()))
result = runner.invoke(["discover"])
assert not result.exception
assert set(result.output.splitlines()) > {
"Discovering collections for pair bambaz",
"Discovering collections for pair foobar",
}
result = runner.invoke(["sync"])
assert not result.exception
assert set(result.output.splitlines()) == {
"Syncing bambaz",
"Syncing foobar",
}
# XXX: https://github.com/pimutils/vdirsyncer/issues/617
@pytest.mark.skipif(sys.platform == "darwin", reason="This test inexplicably fails")
@pytest.mark.parametrize(
"collections",
[
("a", "A"),
("\ufffe",),
("Hello there!",),
("Österreich",),
("中国", "x1"),
("한글",),
("42a4ec99-b1c2-4859-b142-759112f2ca50",),
("فلسطين",),
],
)
def test_create_collections(collections, tmpdir, runner):
runner.write_with_general(
dedent(
f"""
[pair foobar]
a = "foo"
b = "bar"
collections = {json.dumps(list(collections))}
[storage foo]
type = "filesystem"
path = "{tmpdir!s}/foo/"
fileext = ".txt"
[storage bar]
type = "filesystem"
path = "{tmpdir!s}/bar/"
fileext = ".txt"
"""
)
)
result = runner.invoke(["discover"], input="y\n" * 2 * (len(collections) + 1))
assert not result.exception, result.output
result = runner.invoke(["sync"] + ["foobar/" + x for x in collections])
assert not result.exception, result.output
assert {x.basename for x in tmpdir.join("foo").listdir()} == {
x.basename for x in tmpdir.join("bar").listdir()
}
def test_ident_conflict(tmpdir, runner):
runner.write_with_general(
dedent(
f"""
[pair foobar]
a = "foo"
b = "bar"
collections = null
[storage foo]
type = "filesystem"
path = "{tmpdir!s}/foo/"
fileext = ".txt"
[storage bar]
type = "filesystem"
path = "{tmpdir!s}/bar/"
fileext = ".txt"
"""
)
)
foo = tmpdir.mkdir("foo")
tmpdir.mkdir("bar")
foo.join("one.txt").write("UID:1")
foo.join("two.txt").write("UID:1")
foo.join("three.txt").write("UID:1")
result = runner.invoke(["discover"])
assert not result.exception
result = runner.invoke(["sync"])
assert result.exception
assert (
'error: foobar: Storage "foo" contains multiple items with the '
"same UID or even content"
) in result.output
assert sorted(
[
"one.txt" in result.output,
"two.txt" in result.output,
"three.txt" in result.output,
]
) == [False, True, True]
@pytest.mark.parametrize(
("existing", "missing"),
[
("foo", "bar"),
("bar", "foo"),
],
)
def test_unknown_storage(tmpdir, runner, existing, missing):
runner.write_with_general(
dedent(
f"""
[pair foobar]
a = "foo"
b = "bar"
collections = null
[storage {existing}]
type = "filesystem"
path = "{tmpdir!s}/{existing}/"
fileext = ".txt"
"""
)
)
tmpdir.mkdir(existing)
result = runner.invoke(["discover"])
assert result.exception
assert (
f"Storage '{missing}' not found. "
f"These are the configured storages: ['{existing}']"
) in result.output
@pytest.mark.parametrize("cmd", ["sync", "metasync"])
def test_no_configured_pairs(tmpdir, runner, cmd):
runner.write_with_general("")
result = runner.invoke([cmd])
assert result.output == ""
assert not result.exception
@pytest.mark.parametrize(
("resolution", "expect_foo", "expect_bar"),
[(["command", "cp"], "UID:lol\nfööcontent", "UID:lol\nfööcontent")],
)
def test_conflict_resolution(tmpdir, runner, resolution, expect_foo, expect_bar):
runner.write_with_general(
dedent(
f"""
[pair foobar]
a = "foo"
b = "bar"
collections = null
conflict_resolution = {json.dumps(resolution)}
[storage foo]
type = "filesystem"
fileext = ".txt"
path = "{tmpdir!s}/foo"
[storage bar]
type = "filesystem"
fileext = ".txt"
path = "{tmpdir!s}/bar"
"""
)
)
foo = tmpdir.join("foo")
bar = tmpdir.join("bar")
fooitem = foo.join("lol.txt").ensure()
fooitem.write("UID:lol\nfööcontent")
baritem = bar.join("lol.txt").ensure()
baritem.write("UID:lol\nbööcontent")
r = runner.invoke(["discover"])
assert not r.exception
r = runner.invoke(["sync"])
assert not r.exception
assert fooitem.read() == expect_foo
assert baritem.read() == expect_bar
@pytest.mark.parametrize("partial_sync", ["error", "ignore", "revert", None])
def test_partial_sync(tmpdir, runner, partial_sync):
runner.write_with_general(
dedent(
"""
[pair foobar]
a = "foo"
b = "bar"
collections = null
{partial_sync}
[storage foo]
type = "filesystem"
fileext = ".txt"
path = "{base}/foo"
[storage bar]
type = "filesystem"
read_only = true
fileext = ".txt"
path = "{base}/bar"
""".format(
partial_sync=(
f'partial_sync = "{partial_sync}"\n' if partial_sync else ""
),
base=str(tmpdir),
)
)
)
foo = tmpdir.mkdir("foo")
bar = tmpdir.mkdir("bar")
foo.join("other.txt").write("UID:other")
bar.join("other.txt").write("UID:other")
baritem = bar.join("lol.txt")
baritem.write("UID:lol")
r = runner.invoke(["discover"])
assert not r.exception
r = runner.invoke(["sync"])
assert not r.exception
fooitem = foo.join("lol.txt")
fooitem.remove()
r = runner.invoke(["sync"])
if partial_sync == "error":
assert r.exception
assert "Attempted change" in r.output
elif partial_sync == "ignore":
assert baritem.exists()
r = runner.invoke(["sync"])
assert not r.exception
assert baritem.exists()
else:
assert baritem.exists()
r = runner.invoke(["sync"])
assert not r.exception
assert baritem.exists()
assert fooitem.exists()
def test_fetch_only_necessary_params(tmpdir, runner):
fetched_file = tmpdir.join("fetched_flag")
fetch_script = tmpdir.join("fetch_script")
fetch_script.write(
dedent(
f"""
set -e
touch "{fetched_file!s}"
echo ".txt"
"""
)
)
runner.write_with_general(
dedent(
"""
[pair foobar]
a = "foo"
b = "bar"
collections = null
[pair bambar]
a = "bam"
b = "bar"
collections = null
[storage foo]
type = "filesystem"
path = "{path}"
fileext = ".txt"
[storage bar]
type = "filesystem"
path = "{path}"
fileext = ".txt"
[storage bam]
type = "filesystem"
path = "{path}"
fileext.fetch = ["command", "sh", "{script}"]
""".format(path=str(tmpdir.mkdir("bogus")), script=str(fetch_script))
)
)
def fetched():
try:
fetched_file.remove()
return True
except Exception:
return False
r = runner.invoke(["discover"])
assert not r.exception
assert fetched()
r = runner.invoke(["sync", "foobar"])
assert not r.exception
assert not fetched()
r = runner.invoke(["sync"])
assert not r.exception
assert fetched()
r = runner.invoke(["sync", "bambar"])
assert not r.exception
assert fetched()

View file

@ -0,0 +1,31 @@
from __future__ import annotations
import pytest
from vdirsyncer import exceptions
from vdirsyncer.cli.utils import handle_cli_error
from vdirsyncer.cli.utils import storage_instance_from_config
from vdirsyncer.cli.utils import storage_names
def test_handle_cli_error(capsys):
try:
raise exceptions.InvalidResponse("ayy lmao")
except BaseException:
handle_cli_error()
_out, err = capsys.readouterr()
assert "returned something vdirsyncer doesn't understand" in err
assert "ayy lmao" in err
@pytest.mark.asyncio
async def test_storage_instance_from_config(monkeypatch, aio_connector):
class Dummy:
def __init__(self, **kw):
assert kw == {"foo": "bar", "baz": 1}
monkeypatch.setitem(storage_names._storages, "lol", Dummy)
config = {"type": "lol", "foo": "bar", "baz": 1}
storage = await storage_instance_from_config(config, connector=aio_connector)
assert isinstance(storage, Dummy)

28
tests/system/conftest.py Normal file
View file

@ -0,0 +1,28 @@
from __future__ import annotations
import ssl
import pytest
import trustme
@pytest.fixture(scope="session")
def ca():
return trustme.CA()
@pytest.fixture(scope="session")
def localhost_cert(ca):
return ca.issue_cert("localhost")
@pytest.fixture(scope="session")
def httpserver_ssl_context(localhost_cert):
context = ssl.SSLContext(ssl.PROTOCOL_TLS_SERVER)
crt = localhost_cert.cert_chain_pems[0]
key = localhost_cert.private_key_pem
with crt.tempfile() as crt_file, key.tempfile() as key_file:
context.load_cert_chain(crt_file, key_file)
return context

Some files were not shown because too many files have changed in this diff Show more