mirror of
https://github.com/samsonjs/vdirsyncer.git
synced 2026-03-26 09:05:50 +00:00
config: Add warning about unquoted strings
This commit is contained in:
parent
8171c46b10
commit
5a257ec2cd
17 changed files with 281 additions and 274 deletions
|
|
@ -16,6 +16,8 @@ Version 0.14.0
|
|||
exit code in such situations is still non-zero.
|
||||
- Add ``partial_sync`` option to pair section. See :ref:`the config docs
|
||||
<partial_sync_def>`.
|
||||
- Vdirsyner will now warn if there's a string without quotes in your config.
|
||||
Please file issues if you find documentation that uses unquoted strings.
|
||||
|
||||
Version 0.13.1
|
||||
==============
|
||||
|
|
|
|||
|
|
@ -16,8 +16,8 @@ status_path = ~/.vdirsyncer/status/
|
|||
# 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
|
||||
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
|
||||
|
|
@ -37,13 +37,13 @@ metadata = ["displayname"]
|
|||
[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
|
||||
type = "filesystem"
|
||||
path = "~/.contacts/"
|
||||
fileext = ".vcf"
|
||||
|
||||
[storage bob_contacts_remote]
|
||||
type = carddav
|
||||
url = https://owncloud.example.com/remote.php/carddav/
|
||||
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
|
||||
|
|
@ -51,20 +51,20 @@ url = https://owncloud.example.com/remote.php/carddav/
|
|||
|
||||
# CALDAV
|
||||
[pair bob_calendar]
|
||||
a = bob_calendar_local
|
||||
b = bob_calendar_remote
|
||||
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
|
||||
type = "filesystem"
|
||||
path = "~/.calendars/"
|
||||
fileext = ".ics"
|
||||
|
||||
[storage bob_calendar_remote]
|
||||
type = caldav
|
||||
url = https://owncloud.example.com/remote.php/caldav/
|
||||
type = "caldav"
|
||||
url = "https://owncloud.example.com/remote.php/caldav/"
|
||||
#username =
|
||||
#password =
|
||||
|
|
|
|||
|
|
@ -14,24 +14,24 @@ Command
|
|||
Say you have the following configuration::
|
||||
|
||||
[storage foo]
|
||||
type = caldav
|
||||
type = "caldav"
|
||||
url = ...
|
||||
username = foo
|
||||
password = bar
|
||||
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
|
||||
type = "caldav"
|
||||
url = ...
|
||||
username = foo
|
||||
username = "foo"
|
||||
password.fetch = ["command", "~/get-password.sh", "more", "args"]
|
||||
|
||||
You can fetch the username as well::
|
||||
|
||||
[storage foo]
|
||||
type = caldav
|
||||
type = "caldav"
|
||||
url = ...
|
||||
username.fetch = ["command", "~/get-username.sh"]
|
||||
password.fetch = ["command", "~/get-password.sh"]
|
||||
|
|
@ -62,6 +62,6 @@ Password Prompt
|
|||
You can also simply prompt for the password::
|
||||
|
||||
[storage foo]
|
||||
type = caldav
|
||||
username = myusername
|
||||
type = "caldav"
|
||||
username = "myusername"
|
||||
password.fetch = ["prompt", "Password for CalDAV"]
|
||||
|
|
|
|||
|
|
@ -25,17 +25,17 @@ Step 2: Creating the config
|
|||
Paste this into your vdirsyncer config::
|
||||
|
||||
[pair holidays]
|
||||
a = holidays_public
|
||||
b = holidays_private
|
||||
a = "holidays_public"
|
||||
b = "holidays_private"
|
||||
collections = null
|
||||
|
||||
[storage holidays_public]
|
||||
type = http
|
||||
type = "http"
|
||||
# The URL to your iCalendar file.
|
||||
url = ...
|
||||
|
||||
[storage holidays_private]
|
||||
type = caldav
|
||||
type = "caldav"
|
||||
# The direct URL to your calendar.
|
||||
url = ...
|
||||
# The credentials to your CalDAV server
|
||||
|
|
@ -60,8 +60,8 @@ 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
|
||||
a = "holidays_public"
|
||||
b = "holidays_private"
|
||||
collections = null
|
||||
partial_sync = ignore
|
||||
|
||||
|
|
|
|||
|
|
@ -12,7 +12,7 @@ Pinning by fingerprint
|
|||
To pin the certificate by fingerprint::
|
||||
|
||||
[storage foo]
|
||||
type = caldav
|
||||
type = "caldav"
|
||||
...
|
||||
verify_fingerprint = "94:FD:7A:CB:50:75:A4:69:82:0A:F8:23:DF:07:FC:69:3E:CD:90:CA"
|
||||
#verify = false # Optional: Disable CA validation, useful for self-signed certs
|
||||
|
|
@ -32,7 +32,7 @@ Custom root CAs
|
|||
To point vdirsyncer to a custom set of root CAs::
|
||||
|
||||
[storage foo]
|
||||
type = caldav
|
||||
type = "caldav"
|
||||
...
|
||||
verify = "/path/to/cert.pem"
|
||||
|
||||
|
|
@ -62,13 +62,13 @@ 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
|
||||
type = "caldav"
|
||||
...
|
||||
auth_cert = "/path/to/certificate.pem"
|
||||
|
||||
If the key and certificate are separate, a list may be used::
|
||||
|
||||
[storage foo]
|
||||
type = caldav
|
||||
type = "caldav"
|
||||
...
|
||||
auth_cert = ["/path/to/certificate.crt", "/path/to/key.key"]
|
||||
|
|
|
|||
|
|
@ -99,14 +99,14 @@ ownCloud
|
|||
Vdirsyncer is continuously tested against the latest version of ownCloud_::
|
||||
|
||||
[storage cal]
|
||||
type = caldav
|
||||
url = https://example.com/owncloud/remote.php/caldav/
|
||||
type = "caldav"
|
||||
url = "https://example.com/owncloud/remote.php/caldav/"
|
||||
username = ...
|
||||
password = ...
|
||||
|
||||
[storage card]
|
||||
type = carddav
|
||||
url = https://example.com/owncloud/remote.php/carddav/
|
||||
type = "carddav"
|
||||
url = "https://example.com/owncloud/remote.php/carddav/"
|
||||
username = ...
|
||||
password = ...
|
||||
|
||||
|
|
@ -123,14 +123,14 @@ nextCloud
|
|||
Vdirsyncer is continuously tested against the latest version of nextCloud_::
|
||||
|
||||
[storage cal]
|
||||
type = caldav
|
||||
url = https://nextcloud.example.com/
|
||||
type = "caldav"
|
||||
url = "https://nextcloud.example.com/"
|
||||
username = ...
|
||||
password = ...
|
||||
|
||||
[storage card]
|
||||
type = carddav
|
||||
url = https://nextcloud.example.com/
|
||||
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>`_.
|
||||
|
|
@ -147,14 +147,14 @@ with it. `FastMail's support pages
|
|||
the settings to use::
|
||||
|
||||
[storage cal]
|
||||
type = caldav
|
||||
url = https://caldav.messagingengine.com/
|
||||
type = "caldav"
|
||||
url = "https://caldav.messagingengine.com/"
|
||||
username = ...
|
||||
password = ...
|
||||
|
||||
[storage card]
|
||||
type = carddav
|
||||
url = https://carddav.messagingengine.com/
|
||||
type = "carddav"
|
||||
url = "https://carddav.messagingengine.com/"
|
||||
username = ...
|
||||
password = ...
|
||||
|
||||
|
|
@ -170,14 +170,14 @@ Vdirsyncer is irregularly tested against iCloud_.
|
|||
::
|
||||
|
||||
[storage cal]
|
||||
type = caldav
|
||||
url = https://caldav.icloud.com/
|
||||
type = "caldav"
|
||||
url = "https://caldav.icloud.com/"
|
||||
username = ...
|
||||
password = ...
|
||||
|
||||
[storage card]
|
||||
type = carddav
|
||||
url = https://contacts.icloud.com/
|
||||
type = "carddav"
|
||||
url = "https://contacts.icloud.com/"
|
||||
username = ...
|
||||
password = ...
|
||||
|
||||
|
|
@ -202,9 +202,9 @@ special characters and/or using an old DavMail version.
|
|||
**Make absolutely sure you use the latest DavMail**::
|
||||
|
||||
[storage outlook]
|
||||
type = caldav
|
||||
url = http://localhost:1080/
|
||||
username = user@example.com
|
||||
type = "caldav"
|
||||
url = "http://localhost:1080/"
|
||||
username = "user@example.com"
|
||||
password = ...
|
||||
|
||||
- Older versions of DavMail handle URLs case-insensitively. See :gh:`144`.
|
||||
|
|
|
|||
|
|
@ -56,22 +56,22 @@ The following example synchronizes ownCloud's addressbooks to ``~/.contacts/``::
|
|||
|
||||
|
||||
[pair my_contacts]
|
||||
a = my_contacts_local
|
||||
b = my_contacts_remote
|
||||
a = "my_contacts_local"
|
||||
b = "my_contacts_remote"
|
||||
collections = ["from a", "from b"]
|
||||
|
||||
[storage my_contacts_local]
|
||||
type = filesystem
|
||||
path = ~/.contacts/
|
||||
fileext = .vcf
|
||||
type = "filesystem"
|
||||
path = "~/.contacts/"
|
||||
fileext = ".vcf"
|
||||
|
||||
[storage my_contacts_remote]
|
||||
type = carddav
|
||||
type = "carddav"
|
||||
|
||||
# We can simplify this URL here as well. In theory it shouldn't matter.
|
||||
url = https://owncloud.example.com/remote.php/carddav/
|
||||
username = bob
|
||||
password = asdf
|
||||
url = "https://owncloud.example.com/remote.php/carddav/"
|
||||
username = "bob"
|
||||
password = "asdf"
|
||||
|
||||
.. note::
|
||||
|
||||
|
|
@ -127,22 +127,22 @@ 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
|
||||
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
|
||||
type = "filesystem"
|
||||
path = "~/.calendars/"
|
||||
fileext = ".ics"
|
||||
|
||||
[storage my_calendars_remote]
|
||||
type = caldav
|
||||
type = "caldav"
|
||||
|
||||
url = https://owncloud.example.com/remote.php/caldav/
|
||||
username = bob
|
||||
password = asdf
|
||||
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
|
||||
|
|
@ -179,19 +179,19 @@ The last one requires a bit more explanation. Assume this config which
|
|||
synchronizes two directories of addressbooks::
|
||||
|
||||
[pair foobar]
|
||||
a = foo
|
||||
b = bar
|
||||
a = "foo"
|
||||
b = "bar"
|
||||
collections = ["from a", "from b"]
|
||||
|
||||
[storage foo]
|
||||
type = filesystem
|
||||
fileext = .vcf
|
||||
path = ./contacts_foo/
|
||||
type = "filesystem"
|
||||
fileext = ".vcf"
|
||||
path = "./contacts_foo/"
|
||||
|
||||
[storage bar]
|
||||
type = filesystem
|
||||
fileext = .vcf
|
||||
path = ./contacts_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
|
||||
|
|
|
|||
|
|
@ -23,7 +23,7 @@ class _CustomRunner(object):
|
|||
def write_with_general(self, data):
|
||||
self.cfg.write(dedent('''
|
||||
[general]
|
||||
status_path = {}/status/
|
||||
status_path = "{}/status/"
|
||||
''').format(str(self.tmpdir)))
|
||||
self.cfg.write(data, mode='a')
|
||||
|
||||
|
|
|
|||
|
|
@ -43,19 +43,19 @@ def test_read_config(read_config):
|
|||
status_path = /tmp/status/
|
||||
|
||||
[pair bob]
|
||||
a = bob_a
|
||||
b = bob_b
|
||||
a = "bob_a"
|
||||
b = "bob_b"
|
||||
collections = null
|
||||
|
||||
[storage bob_a]
|
||||
type = filesystem
|
||||
path = /tmp/contacts/
|
||||
fileext = .vcf
|
||||
type = "filesystem"
|
||||
path = "/tmp/contacts/"
|
||||
fileext = ".vcf"
|
||||
yesno = false
|
||||
number = 42
|
||||
|
||||
[storage bob_b]
|
||||
type = carddav
|
||||
type = "carddav"
|
||||
''')
|
||||
|
||||
assert c.general == {'status_path': '/tmp/status/'}
|
||||
|
|
@ -79,14 +79,14 @@ def test_missing_collections_param(read_config):
|
|||
status_path = /tmp/status/
|
||||
|
||||
[pair bob]
|
||||
a = bob_a
|
||||
b = bob_b
|
||||
a = "bob_a"
|
||||
b = "bob_b"
|
||||
|
||||
[storage bob_a]
|
||||
type = lmao
|
||||
type = "lmao"
|
||||
|
||||
[storage bob_b]
|
||||
type = lmao
|
||||
type = "lmao"
|
||||
''')
|
||||
|
||||
assert 'collections parameter missing' in str(excinfo.value)
|
||||
|
|
@ -120,19 +120,19 @@ def test_missing_general_section(read_config):
|
|||
with pytest.raises(exceptions.UserError) as excinfo:
|
||||
read_config(u'''
|
||||
[pair my_pair]
|
||||
a = my_a
|
||||
b = my_b
|
||||
a = "my_a"
|
||||
b = "my_b"
|
||||
collections = null
|
||||
|
||||
[storage my_a]
|
||||
type = filesystem
|
||||
path = {base}/path_a/
|
||||
fileext = .txt
|
||||
type = "filesystem"
|
||||
path = "{base}/path_a/"
|
||||
fileext = ".txt"
|
||||
|
||||
[storage my_b]
|
||||
type = filesystem
|
||||
path = {base}/path_b/
|
||||
fileext = .txt
|
||||
type = "filesystem"
|
||||
path = "{base}/path_b/"
|
||||
fileext = ".txt"
|
||||
''')
|
||||
|
||||
assert 'Invalid general section.' in str(excinfo.value)
|
||||
|
|
@ -171,19 +171,19 @@ def test_invalid_collections_arg(read_config):
|
|||
status_path = /tmp/status/
|
||||
|
||||
[pair foobar]
|
||||
a = foo
|
||||
b = bar
|
||||
a = "foo"
|
||||
b = "bar"
|
||||
collections = [null]
|
||||
|
||||
[storage foo]
|
||||
type = filesystem
|
||||
path = /tmp/foo/
|
||||
fileext = .txt
|
||||
type = "filesystem"
|
||||
path = "/tmp/foo/"
|
||||
fileext = ".txt"
|
||||
|
||||
[storage bar]
|
||||
type = filesystem
|
||||
path = /tmp/bar/
|
||||
fileext = .txt
|
||||
type = "filesystem"
|
||||
path = "/tmp/bar/"
|
||||
fileext = ".txt"
|
||||
''')
|
||||
|
||||
assert 'Expected string' in str(excinfo.value)
|
||||
|
|
@ -196,19 +196,19 @@ def test_duplicate_sections(read_config):
|
|||
status_path = /tmp/status/
|
||||
|
||||
[pair foobar]
|
||||
a = foobar
|
||||
b = bar
|
||||
a = "foobar"
|
||||
b = "bar"
|
||||
collections = null
|
||||
|
||||
[storage foobar]
|
||||
type = filesystem
|
||||
path = /tmp/foo/
|
||||
fileext = .txt
|
||||
type = "filesystem"
|
||||
path = "/tmp/foo/"
|
||||
fileext = ".txt"
|
||||
|
||||
[storage bar]
|
||||
type = filesystem
|
||||
path = /tmp/bar/
|
||||
fileext = .txt
|
||||
type = "filesystem"
|
||||
path = "/tmp/bar/"
|
||||
fileext = ".txt"
|
||||
''')
|
||||
|
||||
assert 'Name "foobar" already used' in str(excinfo.value)
|
||||
|
|
@ -219,10 +219,10 @@ def test_parse_config_value(parse_config_value):
|
|||
|
||||
assert x('123 # comment!') is invalid
|
||||
|
||||
assert x('True') == ('True', 1)
|
||||
assert x('False') == ('False', 1)
|
||||
assert x('Yes') == ('Yes', 1)
|
||||
assert x('None') == ('None', 1)
|
||||
assert x('True') is invalid
|
||||
assert x('False') is invalid
|
||||
assert x('Yes') is invalid
|
||||
assert x('None') is invalid
|
||||
assert x('"True"') == ('True', 0)
|
||||
assert x('"False"') == ('False', 0)
|
||||
|
||||
|
|
@ -231,7 +231,7 @@ def test_parse_config_value(parse_config_value):
|
|||
assert x('false') == (False, 0)
|
||||
assert x('null') == (None, 0)
|
||||
assert x('3.14') == (3.14, 0)
|
||||
assert x('') == ('', 0)
|
||||
assert x('') == ('', 1)
|
||||
assert x('""') == ('', 0)
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -1,3 +1,4 @@
|
|||
import json
|
||||
from textwrap import dedent
|
||||
|
||||
import hypothesis.strategies as st
|
||||
|
|
@ -10,18 +11,18 @@ 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
|
||||
type = "filesystem"
|
||||
path = "{0}/foo/"
|
||||
fileext = ".txt"
|
||||
|
||||
[storage bar]
|
||||
type = filesystem
|
||||
path = {0}/bar/
|
||||
fileext = .txt
|
||||
type = "filesystem"
|
||||
path = "{0}/bar/"
|
||||
fileext = ".txt"
|
||||
|
||||
[pair foobar]
|
||||
a = foo
|
||||
b = bar
|
||||
a = "foo"
|
||||
b = "bar"
|
||||
collections = ["from a"]
|
||||
''').format(str(tmpdir)))
|
||||
|
||||
|
|
@ -68,18 +69,18 @@ def test_discover_different_collection_names(tmpdir, runner):
|
|||
bar = tmpdir.mkdir('bar')
|
||||
runner.write_with_general(dedent('''
|
||||
[storage foo]
|
||||
type = filesystem
|
||||
fileext = .txt
|
||||
path = {foo}
|
||||
type = "filesystem"
|
||||
fileext = ".txt"
|
||||
path = "{foo}"
|
||||
|
||||
[storage bar]
|
||||
type = filesystem
|
||||
fileext = .txt
|
||||
path = {bar}
|
||||
type = "filesystem"
|
||||
fileext = ".txt"
|
||||
path = "{bar}"
|
||||
|
||||
[pair foobar]
|
||||
a = foo
|
||||
b = bar
|
||||
a = "foo"
|
||||
b = "bar"
|
||||
collections = [
|
||||
["coll1", "coll_a1", "coll_b1"],
|
||||
"coll2"
|
||||
|
|
@ -114,18 +115,18 @@ def test_discover_direct_path(tmpdir, runner):
|
|||
|
||||
runner.write_with_general(dedent('''
|
||||
[storage foo]
|
||||
type = filesystem
|
||||
fileext = .txt
|
||||
path = {foo}
|
||||
type = "filesystem"
|
||||
fileext = ".txt"
|
||||
path = "{foo}"
|
||||
|
||||
[storage bar]
|
||||
type = filesystem
|
||||
fileext = .txt
|
||||
path = {bar}
|
||||
type = "filesystem"
|
||||
fileext = ".txt"
|
||||
path = "{bar}"
|
||||
|
||||
[pair foobar]
|
||||
a = foo
|
||||
b = bar
|
||||
a = "foo"
|
||||
b = "bar"
|
||||
collections = null
|
||||
''').format(foo=str(foo), bar=str(bar)))
|
||||
|
||||
|
|
@ -142,18 +143,18 @@ def test_discover_direct_path(tmpdir, runner):
|
|||
def test_null_collection_with_named_collection(tmpdir, runner):
|
||||
runner.write_with_general(dedent('''
|
||||
[pair foobar]
|
||||
a = foo
|
||||
b = bar
|
||||
a = "foo"
|
||||
b = "bar"
|
||||
collections = [["baz", "baz", null]]
|
||||
|
||||
[storage foo]
|
||||
type = filesystem
|
||||
path = {base}/foo/
|
||||
fileext = .txt
|
||||
type = "filesystem"
|
||||
path = "{base}/foo/"
|
||||
fileext = ".txt"
|
||||
|
||||
[storage bar]
|
||||
type = singlefile
|
||||
path = {base}/bar.txt
|
||||
type = "singlefile"
|
||||
path = "{base}/bar.txt"
|
||||
'''.format(base=str(tmpdir))))
|
||||
|
||||
result = runner.invoke(['discover'], input='y\n' * 2)
|
||||
|
|
@ -192,18 +193,18 @@ def test_collection_required(a_requires, b_requires, tmpdir, runner,
|
|||
|
||||
runner.write_with_general(dedent('''
|
||||
[pair foobar]
|
||||
a = foo
|
||||
b = bar
|
||||
a = "foo"
|
||||
b = "bar"
|
||||
collections = null
|
||||
|
||||
[storage foo]
|
||||
type = test
|
||||
type = "test"
|
||||
require_collection = {a}
|
||||
|
||||
[storage bar]
|
||||
type = test
|
||||
type = "test"
|
||||
require_collection = {b}
|
||||
'''.format(a=a_requires, b=b_requires)))
|
||||
'''.format(a=json.dumps(a_requires), b=json.dumps(b_requires))))
|
||||
|
||||
result = runner.invoke(['discover'])
|
||||
if a_requires or b_requires:
|
||||
|
|
|
|||
|
|
@ -41,18 +41,18 @@ def value_cache(monkeypatch):
|
|||
def test_get_password_from_command(tmpdir, runner):
|
||||
runner.write_with_general(dedent('''
|
||||
[pair foobar]
|
||||
a = foo
|
||||
b = bar
|
||||
a = "foo"
|
||||
b = "bar"
|
||||
collections = ["a", "b", "c"]
|
||||
|
||||
[storage foo]
|
||||
type = filesystem
|
||||
path = {base}/foo/
|
||||
type = "filesystem"
|
||||
path = "{base}/foo/"
|
||||
fileext.fetch = ["command", "echo", ".txt"]
|
||||
|
||||
[storage bar]
|
||||
type = filesystem
|
||||
path = {base}/bar/
|
||||
type = "filesystem"
|
||||
path = "{base}/bar/"
|
||||
fileext.fetch = ["prompt", "Fileext for bar"]
|
||||
'''.format(base=str(tmpdir))))
|
||||
|
||||
|
|
|
|||
|
|
@ -9,9 +9,9 @@ import pytest
|
|||
def test_full(tmpdir, runner, collection):
|
||||
runner.write_with_general(dedent('''
|
||||
[storage foo]
|
||||
type = filesystem
|
||||
path = {base}/foo/
|
||||
fileext = .txt
|
||||
type = "filesystem"
|
||||
path = "{base}/foo/"
|
||||
fileext = ".txt"
|
||||
''').format(base=str(tmpdir)))
|
||||
|
||||
storage = tmpdir.mkdir('foo')
|
||||
|
|
|
|||
|
|
@ -13,19 +13,19 @@ import pytest
|
|||
def test_simple_run(tmpdir, runner):
|
||||
runner.write_with_general(dedent('''
|
||||
[pair my_pair]
|
||||
a = my_a
|
||||
b = my_b
|
||||
a = "my_a"
|
||||
b = "my_b"
|
||||
collections = null
|
||||
|
||||
[storage my_a]
|
||||
type = filesystem
|
||||
path = {0}/path_a/
|
||||
fileext = .txt
|
||||
type = "filesystem"
|
||||
path = "{0}/path_a/"
|
||||
fileext = ".txt"
|
||||
|
||||
[storage my_b]
|
||||
type = filesystem
|
||||
path = {0}/path_b/
|
||||
fileext = .txt
|
||||
type = "filesystem"
|
||||
path = "{0}/path_b/"
|
||||
fileext = ".txt"
|
||||
''').format(str(tmpdir)))
|
||||
|
||||
tmpdir.mkdir('path_a')
|
||||
|
|
@ -54,19 +54,19 @@ def test_sync_inexistant_pair(tmpdir, runner):
|
|||
def test_debug_connections(tmpdir, runner):
|
||||
runner.write_with_general(dedent('''
|
||||
[pair my_pair]
|
||||
a = my_a
|
||||
b = my_b
|
||||
a = "my_a"
|
||||
b = "my_b"
|
||||
collections = null
|
||||
|
||||
[storage my_a]
|
||||
type = filesystem
|
||||
path = {0}/path_a/
|
||||
fileext = .txt
|
||||
type = "filesystem"
|
||||
path = "{0}/path_a/"
|
||||
fileext = ".txt"
|
||||
|
||||
[storage my_b]
|
||||
type = filesystem
|
||||
path = {0}/path_b/
|
||||
fileext = .txt
|
||||
type = "filesystem"
|
||||
path = "{0}/path_b/"
|
||||
fileext = ".txt"
|
||||
''').format(str(tmpdir)))
|
||||
|
||||
tmpdir.mkdir('path_a')
|
||||
|
|
@ -85,19 +85,19 @@ def test_debug_connections(tmpdir, runner):
|
|||
def test_empty_storage(tmpdir, runner):
|
||||
runner.write_with_general(dedent('''
|
||||
[pair my_pair]
|
||||
a = my_a
|
||||
b = my_b
|
||||
a = "my_a"
|
||||
b = "my_b"
|
||||
collections = null
|
||||
|
||||
[storage my_a]
|
||||
type = filesystem
|
||||
path = {0}/path_a/
|
||||
fileext = .txt
|
||||
type = "filesystem"
|
||||
path = "{0}/path_a/"
|
||||
fileext = ".txt"
|
||||
|
||||
[storage my_b]
|
||||
type = filesystem
|
||||
path = {0}/path_b/
|
||||
fileext = .txt
|
||||
type = "filesystem"
|
||||
path = "{0}/path_b/"
|
||||
fileext = ".txt"
|
||||
''').format(str(tmpdir)))
|
||||
|
||||
tmpdir.mkdir('path_a')
|
||||
|
|
@ -137,18 +137,18 @@ def test_collections_cache_invalidation(tmpdir, runner):
|
|||
|
||||
runner.write_with_general(dedent('''
|
||||
[storage foo]
|
||||
type = filesystem
|
||||
path = {0}/foo/
|
||||
fileext = .txt
|
||||
type = "filesystem"
|
||||
path = "{0}/foo/"
|
||||
fileext = ".txt"
|
||||
|
||||
[storage bar]
|
||||
type = filesystem
|
||||
path = {0}/bar/
|
||||
fileext = .txt
|
||||
type = "filesystem"
|
||||
path = "{0}/bar/"
|
||||
fileext = ".txt"
|
||||
|
||||
[pair foobar]
|
||||
a = foo
|
||||
b = bar
|
||||
a = "foo"
|
||||
b = "bar"
|
||||
collections = ["a", "b", "c"]
|
||||
''').format(str(tmpdir)))
|
||||
|
||||
|
|
@ -167,18 +167,18 @@ def test_collections_cache_invalidation(tmpdir, runner):
|
|||
|
||||
runner.write_with_general(dedent('''
|
||||
[storage foo]
|
||||
type = filesystem
|
||||
path = {0}/foo/
|
||||
fileext = .txt
|
||||
type = "filesystem"
|
||||
path = "{0}/foo/"
|
||||
fileext = ".txt"
|
||||
|
||||
[storage bar]
|
||||
type = filesystem
|
||||
path = {0}/bar2/
|
||||
fileext = .txt
|
||||
type = "filesystem"
|
||||
path = "{0}/bar2/"
|
||||
fileext = ".txt"
|
||||
|
||||
[pair foobar]
|
||||
a = foo
|
||||
b = bar
|
||||
a = "foo"
|
||||
b = "bar"
|
||||
collections = ["a", "b", "c"]
|
||||
''').format(str(tmpdir)))
|
||||
|
||||
|
|
@ -207,18 +207,18 @@ def test_collections_cache_invalidation(tmpdir, runner):
|
|||
def test_invalid_pairs_as_cli_arg(tmpdir, runner):
|
||||
runner.write_with_general(dedent('''
|
||||
[storage foo]
|
||||
type = filesystem
|
||||
path = {0}/foo/
|
||||
fileext = .txt
|
||||
type = "filesystem"
|
||||
path = "{0}/foo/"
|
||||
fileext = ".txt"
|
||||
|
||||
[storage bar]
|
||||
type = filesystem
|
||||
path = {0}/bar/
|
||||
fileext = .txt
|
||||
type = "filesystem"
|
||||
path = "{0}/bar/"
|
||||
fileext = ".txt"
|
||||
|
||||
[pair foobar]
|
||||
a = foo
|
||||
b = bar
|
||||
a = "foo"
|
||||
b = "bar"
|
||||
collections = ["a", "b", "c"]
|
||||
''').format(str(tmpdir)))
|
||||
|
||||
|
|
@ -240,17 +240,17 @@ def test_multiple_pairs(tmpdir, runner):
|
|||
for name_a, name_b in ('foo', 'bar'), ('bam', 'baz'):
|
||||
yield dedent('''
|
||||
[pair {a}{b}]
|
||||
a = {a}
|
||||
b = {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
|
||||
type = "filesystem"
|
||||
path = "{path}"
|
||||
fileext = ".txt"
|
||||
''').format(name=name, path=str(tmpdir.mkdir(name)))
|
||||
|
||||
runner.write_with_general(''.join(get_cfg()))
|
||||
|
|
@ -291,19 +291,19 @@ def test_create_collections(subtest, collections):
|
|||
def test_inner(tmpdir, runner):
|
||||
runner.write_with_general(dedent('''
|
||||
[pair foobar]
|
||||
a = foo
|
||||
b = bar
|
||||
a = "foo"
|
||||
b = "bar"
|
||||
collections = {colls}
|
||||
|
||||
[storage foo]
|
||||
type = filesystem
|
||||
path = {base}/foo/
|
||||
fileext = .txt
|
||||
type = "filesystem"
|
||||
path = "{base}/foo/"
|
||||
fileext = ".txt"
|
||||
|
||||
[storage bar]
|
||||
type = filesystem
|
||||
path = {base}/bar/
|
||||
fileext = .txt
|
||||
type = "filesystem"
|
||||
path = "{base}/bar/"
|
||||
fileext = ".txt"
|
||||
'''.format(base=str(tmpdir), colls=json.dumps(list(collections)))))
|
||||
|
||||
result = runner.invoke(
|
||||
|
|
@ -337,19 +337,19 @@ def test_create_collections(subtest, collections):
|
|||
def test_ident_conflict(tmpdir, runner):
|
||||
runner.write_with_general(dedent('''
|
||||
[pair foobar]
|
||||
a = foo
|
||||
b = bar
|
||||
a = "foo"
|
||||
b = "bar"
|
||||
collections = null
|
||||
|
||||
[storage foo]
|
||||
type = filesystem
|
||||
path = {base}/foo/
|
||||
fileext = .txt
|
||||
type = "filesystem"
|
||||
path = "{base}/foo/"
|
||||
fileext = ".txt"
|
||||
|
||||
[storage bar]
|
||||
type = filesystem
|
||||
path = {base}/bar/
|
||||
fileext = .txt
|
||||
type = "filesystem"
|
||||
path = "{base}/bar/"
|
||||
fileext = ".txt"
|
||||
'''.format(base=str(tmpdir))))
|
||||
|
||||
foo = tmpdir.mkdir('foo')
|
||||
|
|
@ -380,14 +380,14 @@ def test_ident_conflict(tmpdir, runner):
|
|||
def test_unknown_storage(tmpdir, runner, existing, missing):
|
||||
runner.write_with_general(dedent('''
|
||||
[pair foobar]
|
||||
a = foo
|
||||
b = bar
|
||||
a = "foo"
|
||||
b = "bar"
|
||||
collections = null
|
||||
|
||||
[storage {existing}]
|
||||
type = filesystem
|
||||
path = {base}/{existing}/
|
||||
fileext = .txt
|
||||
type = "filesystem"
|
||||
path = "{base}/{existing}/"
|
||||
fileext = ".txt"
|
||||
'''.format(base=str(tmpdir), existing=existing)))
|
||||
|
||||
tmpdir.mkdir(existing)
|
||||
|
|
@ -418,20 +418,20 @@ def test_conflict_resolution(tmpdir, runner, resolution, expect_foo,
|
|||
expect_bar):
|
||||
runner.write_with_general(dedent('''
|
||||
[pair foobar]
|
||||
a = foo
|
||||
b = bar
|
||||
a = "foo"
|
||||
b = "bar"
|
||||
collections = null
|
||||
conflict_resolution = {val}
|
||||
|
||||
[storage foo]
|
||||
type = filesystem
|
||||
fileext = .txt
|
||||
path = {base}/foo
|
||||
type = "filesystem"
|
||||
fileext = ".txt"
|
||||
path = "{base}/foo"
|
||||
|
||||
[storage bar]
|
||||
type = filesystem
|
||||
fileext = .txt
|
||||
path = {base}/bar
|
||||
type = "filesystem"
|
||||
fileext = ".txt"
|
||||
path = "{base}/bar"
|
||||
'''.format(base=str(tmpdir), val=json.dumps(resolution))))
|
||||
|
||||
foo = tmpdir.join('foo')
|
||||
|
|
@ -455,21 +455,21 @@ def test_conflict_resolution(tmpdir, runner, resolution, expect_foo,
|
|||
def test_partial_sync(tmpdir, runner, partial_sync):
|
||||
runner.write_with_general(dedent('''
|
||||
[pair foobar]
|
||||
a = foo
|
||||
b = bar
|
||||
a = "foo"
|
||||
b = "bar"
|
||||
collections = null
|
||||
{partial_sync}
|
||||
|
||||
[storage foo]
|
||||
type = filesystem
|
||||
fileext = .txt
|
||||
path = {base}/foo
|
||||
type = "filesystem"
|
||||
fileext = ".txt"
|
||||
path = "{base}/foo"
|
||||
|
||||
[storage bar]
|
||||
type = filesystem
|
||||
type = "filesystem"
|
||||
read_only = true
|
||||
fileext = .txt
|
||||
path = {base}/bar
|
||||
fileext = ".txt"
|
||||
path = "{base}/bar"
|
||||
'''.format(
|
||||
partial_sync=('partial_sync = {}\n'.format(partial_sync)
|
||||
if partial_sync else ''),
|
||||
|
|
@ -523,28 +523,28 @@ def test_fetch_only_necessary_params(tmpdir, runner):
|
|||
|
||||
runner.write_with_general(dedent('''
|
||||
[pair foobar]
|
||||
a = foo
|
||||
b = bar
|
||||
a = "foo"
|
||||
b = "bar"
|
||||
collections = null
|
||||
|
||||
[pair bambar]
|
||||
a = bam
|
||||
b = bar
|
||||
a = "bam"
|
||||
b = "bar"
|
||||
collections = null
|
||||
|
||||
[storage foo]
|
||||
type = filesystem
|
||||
path = {path}
|
||||
fileext = .txt
|
||||
type = "filesystem"
|
||||
path = "{path}"
|
||||
fileext = ".txt"
|
||||
|
||||
[storage bar]
|
||||
type = filesystem
|
||||
path = {path}
|
||||
fileext = .txt
|
||||
type = "filesystem"
|
||||
path = "{path}"
|
||||
fileext = ".txt"
|
||||
|
||||
[storage bam]
|
||||
type = filesystem
|
||||
path = {path}
|
||||
type = "filesystem"
|
||||
path = "{path}"
|
||||
fileext.fetch = ["command", "sh", "{script}"]
|
||||
'''.format(path=str(tmpdir.mkdir('bogus')), script=str(fetch_script))))
|
||||
|
||||
|
|
|
|||
|
|
@ -71,7 +71,7 @@ def test_list(monkeypatch):
|
|||
|
||||
|
||||
def test_readonly_param():
|
||||
url = u'http://example.com/'
|
||||
url = 'http://example.com/'
|
||||
with pytest.raises(ValueError):
|
||||
HttpStorage(url=url, read_only=False)
|
||||
|
||||
|
|
|
|||
|
|
@ -158,9 +158,9 @@ def _parse_config_value(value):
|
|||
(('none',), 'null')
|
||||
]:
|
||||
if value.lower() in wrong + (right,):
|
||||
cli_logger.warning('You probably meant {} instead of "{}", which '
|
||||
'will now be interpreted as a literal string.'
|
||||
.format(right, value))
|
||||
raise ValueError('You probably meant {} instead of {}. Surround '
|
||||
'your string with double-quotes if not.'
|
||||
.format(right, value))
|
||||
|
||||
if '#' in value:
|
||||
raise ValueError('Invalid value:{}\n'
|
||||
|
|
@ -176,6 +176,10 @@ def _parse_config_value(value):
|
|||
# # my comment
|
||||
raise ValueError('No multiline-values allowed:\n{}'.format(value))
|
||||
|
||||
cli_logger.warning('Soon, all strings have to be in double quotes. Please '
|
||||
'replace {} with {}'
|
||||
.format(value, json.dumps(value)))
|
||||
|
||||
return value
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -117,12 +117,12 @@ class HttpStorage(Storage):
|
|||
collections = null
|
||||
|
||||
[storage holidays_local]
|
||||
type = filesystem
|
||||
type = "filesystem"
|
||||
path = ~/.config/vdir/calendars/holidays/
|
||||
fileext = .ics
|
||||
|
||||
[storage holidays_remote]
|
||||
type = http
|
||||
type = "http"
|
||||
url = https://example.com/holidays_from_hicksville.ics
|
||||
'''
|
||||
|
||||
|
|
|
|||
|
|
@ -53,11 +53,11 @@ class SingleFileStorage(Storage):
|
|||
collections = ["from a", "from b"]
|
||||
|
||||
[storage my_calendar_local]
|
||||
type = singlefile
|
||||
type = "singlefile"
|
||||
path = ~/.calendars/%s.ics
|
||||
|
||||
[storage my_calendar_remote]
|
||||
type = caldav
|
||||
type = "caldav"
|
||||
url = https://caldav.example.org/
|
||||
#username =
|
||||
#password =
|
||||
|
|
@ -69,11 +69,11 @@ class SingleFileStorage(Storage):
|
|||
b = my_calendar_remote
|
||||
|
||||
[storage my_calendar_local]
|
||||
type = singlefile
|
||||
type = "singlefile"
|
||||
path = ~/my_calendar.ics
|
||||
|
||||
[storage my_calendar_remote]
|
||||
type = caldav
|
||||
type = "caldav"
|
||||
url = https://caldav.example.org/username/my_calendar/
|
||||
#username =
|
||||
#password =
|
||||
|
|
|
|||
Loading…
Reference in a new issue