summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTobias Brox <tobias@redpill-linpro.com>2022-12-03 20:22:09 +0100
committerTobias Brox <tobias@redpill-linpro.com>2022-12-03 20:22:09 +0100
commitf8ed2e12c456abed6ce491f92e4e9784f9d0cf50 (patch)
treecacc665bfcbac9a05404c16ccd5d1cc4378050a3
parentcfea5bde72e2d28ff7d409e40f51fa6e6f2b3a7a (diff)
downloadcalendar-cli-f8ed2e12c456abed6ce491f92e4e9784f9d0cf50.zip
more work on configuration and misc
-rw-r--r--README.md51
-rw-r--r--USER_GUIDE.md30
-rwxr-xr-xcalendar_cli/cal.py65
-rwxr-xr-xcalendar_cli/legacy.py3
4 files changed, 127 insertions, 22 deletions
diff --git a/README.md b/README.md
index f298b32..0622e88 100644
--- a/README.md
+++ b/README.md
@@ -127,7 +127,7 @@ The file TASK_MANAGEMENT.md contains some thoughts on how to organize tasks.
Configuration file
------------------
-Configuration file is by default located in $HOME/.config/calendar.conf and should be in json syntax. You may run `calendar-cli --interactive-config` if you don't feel comfortable with hand-crafting configuration in json syntax, though this feature is not tested regularly.
+Configuration file is by default located in $HOME/.config/calendar.conf. calendar-cli expects it to be in json syntax, kal also accepts yaml format. You may run `calendar-cli --interactive-config` if you don't feel comfortable with hand-crafting configuration in json syntax, though this feature is not tested regularly.
(I considered a configuration file in .ini-format, having a "default"-section with default values for any global options, and optionally other sections for different CalDAV-servers. Asking a bit around for recommendations on config file format as well as location, I was told that the .ini-format is not a standard, I'd be better off using a standard like yaml, json or xml. Personally I like json a bit better than yaml - after consulting with a friend I ended up with json. Location ... I think it's "cleaner" to keep it in ~/.config/, and I'd like any calendar application to be able to access the file, hence it got ~/.config/calendar.conf rather than ~/.calendar-cli.conf)
@@ -158,7 +158,54 @@ A configuration with multiple sections may look like this:
}
```
-Optionally, in addition (or even instead) of "default", other "sections" can be created and selected through the --config-section option. The rationale is to allow configuration for multiple CalDAV-servers, or multiple calendars on the same CalDAV-server to remain in the same configuration file. Later versions will eventually be capable of copying events, or putting events into several calendars.
+Sections may also include calendar urls or ids, and sections may inherit other sections:
+
+```json
+{
+"default":
+ { "caldav_url": "http://foo.bar.example.com/caldav/",
+ "caldav_user": "luser",
+ "caldav_pass": "insecure"
+ },
+"baz":
+ { "caldav_url": "http://foo.baz.example.com/caldav/",
+ "caldav_user": "luser2",
+ "caldav_pass": "insecure2"
+ }
+},
+"bazimportant":
+ { "inherits": "baz",
+ "calendar_url": "important"
+ }
+```
+
+kal also accepts `calendar_name`, which should match with the display name.
+
+kal may operate at many calendars at one time, hence it's possible to make a section refer to multiple other sections, like this:
+
+```yaml
+---
+work-calendar:
+ caldav_url: "http://acme.example.com/caldav/"
+ caldav_user: drjekyll
+ caldav_pass: pencilin
+ calendar_url: mycalendar
+work-appointments:
+ inherits: work-calendar
+ calendar_url: mypatients
+private-calendar:
+ caldav_url: "https://ecloud.global/remote.php/dav/"
+ caldav_user: myhyde
+ caldav_pass: hunter2
+ calendar_name: goodgames
+sinuous-deeds:
+ inheritate private-calendar
+ calendar_name: badgames
+work:
+ contains: [ 'work-calendar', 'work-appointments' ]
+private:
+ contains: [ 'privat-calendar', 'sinous-deeds' ]
+```
Remember to `chmod og-r ~/.config/calendar.conf` or `chmod 0600 ~/.config/calendar.conf`
diff --git a/USER_GUIDE.md b/USER_GUIDE.md
index 50a4a4f..fcfc10a 100644
--- a/USER_GUIDE.md
+++ b/USER_GUIDE.md
@@ -20,7 +20,7 @@ kal command subcommand --help
## Main commands
-* test - verify that it's possible to connect to the server
+* list-calendars - verify that it's possible to connect to the server(s) and show the calendar(s) selected
* add - for adding things to the calendar(s)
* select - for selecting, viewing, editing and deleting things from the calendar(s).
@@ -36,7 +36,33 @@ It's recommended to rather use a config file (though not yet supported as of 202
* `--config-file`
* `--config-section`
-The default (though not yet supported as of 2022-10-09) is to utilize the `default` section under `$HOME/.config/calendar.conf`
+The default is to utilize the `default` section under `$HOME/.config/calendar.conf` Here is an example configuration file:
+
+```yaml
+---
+work-calendar:
+ caldav_url: "http://acme.example.com/caldav/"
+ caldav_user: drjekyll
+ caldav_pass: pencilin
+ calendar_url: mycalendar
+work-appointments:
+ inherits: work-calendar
+ calendar_url: mypatients
+private-calendar:
+ caldav_url: "https://ecloud.global/remote.php/dav/"
+ caldav_user: myhyde
+ caldav_pass: hunter2
+ calendar_name: goodgames
+sinuous-deeds:
+ inheritate private-calendar
+ calendar_name: badgames
+work:
+ contains: [ 'work-calendar', 'work-appointments' ]
+private:
+ contains: [ 'privat-calendar', 'sinous-deeds' ]
+```
+
+(TODO: the example above haven't been tested)
Multiple config sections can be specified, which may be useful for selecting things from multiple calendars.
diff --git a/calendar_cli/cal.py b/calendar_cli/cal.py
index 3f54dbd..8be1b60 100755
--- a/calendar_cli/cal.py
+++ b/calendar_cli/cal.py
@@ -34,7 +34,7 @@ import logging
import re
from icalendar import prop, Timezone
from calendar_cli.template import Template
-from calendar_cli.config import interactive_config, config_section, read_config
+from calendar_cli.config import interactive_config, config_section, read_config, expand_config_section
list_type = list
@@ -142,7 +142,7 @@ def parse_timespec(timespec):
raise NotImplementedError("possibly a ISO time interval")
-def find_calendars(args):
+def find_calendars(args, raise_errors):
def list_(obj):
"""
For backward compatibility, a string rather than a list can be given as
@@ -154,6 +154,18 @@ def find_calendars(args):
obj = [ obj ]
return obj
+ def _try(meth, kwargs, errmsg):
+ try:
+ ret = meth(**kwargs)
+ assert(ret)
+ return ret
+ except:
+ logging.error("Problems fetching calendar information: %s - skipping" % errmsg)
+ if raise_errors:
+ raise
+ else:
+ return None
+
conn_params = {}
for k in args:
if k.startswith('caldav_') and args[k]:
@@ -166,27 +178,37 @@ def find_calendars(args):
calendars = []
if conn_params:
client = caldav.DAVClient(**conn_params)
- principal = client.principal()
+ principal = _try(client.principal, {}, conn_params['url'])
+ if not principal:
+ return []
calendars = []
+ tries = 0
for calendar_url in list_(args.get('calendar_url')):
- calendars.append(principal.calendar(cal_id=calendar_url))
+ calendar=principal.calendar(cal_id=calendar_url)
+ tries += 1
+ if _try(calendar.get_display_name, {}, calendar.url):
+ calendars.append(calendar)
for calendar_name in list_(args.get('calendar_name')):
- calendars.append(principal.calendar(name=calendar_name))
- if not calendars:
- calendars = principal.calendars()
- return calendars
+ tries += 1
+ calendar = _try(principal.calendar, {'name': calendar_name}, '%s : calendar "%s"' % (conn_params['url'], calendar_name))
+ calendars.append(calendar)
+ if not calendars and tries == 0:
+ calendars = _try(principal.calendars, {}, "conn_params['url'] - all calendars")
+ return calendars or []
@click.group()
## TODO: interactive config building
## TODO: language and timezone
@click.option('-c', '--config-file', default=f"{os.environ['HOME']}/.config/calendar.conf")
+@click.option('--skip-config/--read-config', help="Skip reading the config file")
@click.option('--config-section', default=["default"], multiple=True)
@click.option('--caldav-url', help="Full URL to the caldav server", metavar='URL')
@click.option('--caldav-username', '--caldav-user', help="Full URL to the caldav server", metavar='URL')
@click.option('--caldav-password', '--caldav-pass', help="Full URL to the caldav server", metavar='URL')
@click.option('--calendar-url', help="Calendar id, path or URL", metavar='cal', multiple=True)
@click.option('--calendar-name', help="Calendar name", metavar='cal', multiple=True)
+@click.option('--raise-errors/--print-errors', help="Raise errors found on calendar discovery")
@click.pass_context
def cli(ctx, **kwargs):
"""
@@ -204,22 +226,33 @@ def cli(ctx, **kwargs):
## TODO: delayed communication with caldav server (i.e. if --help is given to subcommand)
## TODO: catch errors, present nice error messages
conns = []
- ctx.obj['calendars'] = find_calendars(kwargs)
- config = read_config(kwargs['config_file'])
- if config:
- for section in kwargs['config_section']:
- ctx.obj['calendars'].extend(find_calendars(config_section(config, section)))
+ ctx.obj['calendars'] = find_calendars(kwargs, kwargs['raise_errors'])
+ if not kwargs['skip_config']:
+ config = read_config(kwargs['config_file'])
+ if config:
+ for meta_section in kwargs['config_section']:
+ for section in expand_config_section(config, meta_section):
+ ctx.obj['calendars'].extend(find_calendars(config_section(config, section), raise_errors=kwargs['raise_errors']))
+
+@cli.command()
+@click.pass_context
+def interactive_config(ctx):
+ raise NotImplementedError()
@cli.command()
@click.pass_context
-def test(ctx):
+def list_calendars(ctx):
"""
- Will test that we can connect to the caldav server and find the calendars.
+ Will output all calendars found
"""
if not ctx.obj['calendars']:
_abort("No calendars found!")
else:
- click.echo("Seems like everything is OK")
+ output = "Accessible calendars found:\n"
+ calendar_info = [(x.get_display_name(), x.url) for x in ctx.obj['calendars']]
+ max_display_name = max([len(x[0]) for x in calendar_info])
+ format_str= "%%-%ds %%s" % max_display_name
+ click.echo_via_pager(output + "\n".join([format_str % x for x in calendar_info]) + "\n")
def _set_attr_options_(func, verb):
"""
diff --git a/calendar_cli/legacy.py b/calendar_cli/legacy.py
index cf17bd5..6e15715 100755
--- a/calendar_cli/legacy.py
+++ b/calendar_cli/legacy.py
@@ -11,7 +11,6 @@ Copyright (C) 2013-2022 Tobias Brox and other contributors.
See https://www.gnu.org/licenses/gpl-3.0.en.html for license information.
"""
-
import argparse
import tzlocal
## we still need to use pytz, see https://github.com/collective/icalendar/issues/333
@@ -26,7 +25,7 @@ from datetime import time as time_
import dateutil.parser
from dateutil.rrule import rrulestr
from icalendar import Calendar,Event,Todo,Journal,Alarm
-from calendar_cli.config import interactive_config, config_section
+from calendar_cli.config import interactive_config, config_section, read_config
import vobject
import caldav
import uuid