From 5a257ec2cd00fe328bd2c7c2713665d37f18cd8e Mon Sep 17 00:00:00 2001 From: Markus Unterwaditzer Date: Sun, 23 Oct 2016 00:56:26 +0200 Subject: [PATCH] config: Add warning about unquoted strings --- CHANGELOG.rst | 2 + config.example | 28 ++--- docs/keyring.rst | 16 +-- docs/partial-sync.rst | 12 +- docs/ssl-tutorial.rst | 8 +- docs/supported.rst | 38 +++--- docs/tutorial.rst | 52 ++++---- tests/cli/conftest.py | 2 +- tests/cli/test_config.py | 78 ++++++------ tests/cli/test_discover.py | 73 +++++------ tests/cli/test_fetchparams.py | 12 +- tests/cli/test_repair.py | 6 +- tests/cli/test_sync.py | 204 +++++++++++++++---------------- tests/storage/test_http.py | 2 +- vdirsyncer/cli/config.py | 10 +- vdirsyncer/storage/http.py | 4 +- vdirsyncer/storage/singlefile.py | 8 +- 17 files changed, 281 insertions(+), 274 deletions(-) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index ac60624..6de9c25 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -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 `. +- 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 ============== diff --git a/config.example b/config.example index 8a1649a..7027bfb 100644 --- a/config.example +++ b/config.example @@ -16,8 +16,8 @@ status_path = ~/.vdirsyncer/status/ # A `[pair ]` block defines two storages `a` and `b` that should be # synchronized. The definition of these storages follows in `[storage ]` # 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 = diff --git a/docs/keyring.rst b/docs/keyring.rst index b8abef8..eb3d39d 100644 --- a/docs/keyring.rst +++ b/docs/keyring.rst @@ -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"] diff --git a/docs/partial-sync.rst b/docs/partial-sync.rst index 1c776a9..bdedd1f 100644 --- a/docs/partial-sync.rst +++ b/docs/partial-sync.rst @@ -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 diff --git a/docs/ssl-tutorial.rst b/docs/ssl-tutorial.rst index a4fc994..9ce2c04 100644 --- a/docs/ssl-tutorial.rst +++ b/docs/ssl-tutorial.rst @@ -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"] diff --git a/docs/supported.rst b/docs/supported.rst index 8a3e73a..897af65 100644 --- a/docs/supported.rst +++ b/docs/supported.rst @@ -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 `_. @@ -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`. diff --git a/docs/tutorial.rst b/docs/tutorial.rst index 2fefc47..efc30e1 100644 --- a/docs/tutorial.rst +++ b/docs/tutorial.rst @@ -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 diff --git a/tests/cli/conftest.py b/tests/cli/conftest.py index 3d925b1..e6876af 100644 --- a/tests/cli/conftest.py +++ b/tests/cli/conftest.py @@ -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') diff --git a/tests/cli/test_config.py b/tests/cli/test_config.py index 5563f3e..b0cf724 100644 --- a/tests/cli/test_config.py +++ b/tests/cli/test_config.py @@ -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) diff --git a/tests/cli/test_discover.py b/tests/cli/test_discover.py index 0770bca..6355232 100644 --- a/tests/cli/test_discover.py +++ b/tests/cli/test_discover.py @@ -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: diff --git a/tests/cli/test_fetchparams.py b/tests/cli/test_fetchparams.py index 263fc9d..8c010ba 100644 --- a/tests/cli/test_fetchparams.py +++ b/tests/cli/test_fetchparams.py @@ -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)))) diff --git a/tests/cli/test_repair.py b/tests/cli/test_repair.py index 19fd03c..ce234c4 100644 --- a/tests/cli/test_repair.py +++ b/tests/cli/test_repair.py @@ -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') diff --git a/tests/cli/test_sync.py b/tests/cli/test_sync.py index ebbf2f5..8b6e4f7 100644 --- a/tests/cli/test_sync.py +++ b/tests/cli/test_sync.py @@ -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)))) diff --git a/tests/storage/test_http.py b/tests/storage/test_http.py index 7c3fac6..da14d5d 100644 --- a/tests/storage/test_http.py +++ b/tests/storage/test_http.py @@ -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) diff --git a/vdirsyncer/cli/config.py b/vdirsyncer/cli/config.py index 688c024..a721f9b 100644 --- a/vdirsyncer/cli/config.py +++ b/vdirsyncer/cli/config.py @@ -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 diff --git a/vdirsyncer/storage/http.py b/vdirsyncer/storage/http.py index 6c29a9c..551f240 100644 --- a/vdirsyncer/storage/http.py +++ b/vdirsyncer/storage/http.py @@ -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 ''' diff --git a/vdirsyncer/storage/singlefile.py b/vdirsyncer/storage/singlefile.py index b72e47b..689b37a 100644 --- a/vdirsyncer/storage/singlefile.py +++ b/vdirsyncer/storage/singlefile.py @@ -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 =