summaryrefslogtreecommitdiff
path: root/calendar-cli.py
diff options
context:
space:
mode:
authorTobias Brox <tobias@redpill-linpro.com>2015-04-15 21:12:24 +0200
committerTobias Brox <tobias@redpill-linpro.com>2015-04-15 21:12:24 +0200
commit84021ac16ba15d2864c91c86bb694877ed8afe43 (patch)
tree74eafcd9d6785344582474e4e64af2df8aaa7f94 /calendar-cli.py
parent259e1e2dad457a61e28fa6f756afa5c431b6f1ec (diff)
parentb46e0ce53a872ad68555bf53e830b74f079221a2 (diff)
downloadcalendar-cli-84021ac16ba15d2864c91c86bb694877ed8afe43.zip
Merge remote-tracking branch 'refs/remotes/origin/master'
Diffstat (limited to 'calendar-cli.py')
-rwxr-xr-xcalendar-cli.py117
1 files changed, 110 insertions, 7 deletions
diff --git a/calendar-cli.py b/calendar-cli.py
index 2f3ece6..ee46699 100755
--- a/calendar-cli.py
+++ b/calendar-cli.py
@@ -3,9 +3,9 @@
## (the icalendar library is not ported to python3?)
import argparse
-import urlparse
import pytz
import tzlocal
+import time
from datetime import datetime, timedelta
import dateutil.parser
from icalendar import Calendar,Event
@@ -102,6 +102,78 @@ def calendar_addics(caldav_conn, args):
for uid in uids:
c.subcomponents = timezones + uids[uid]
_calendar_addics(caldav_conn, c.to_ical(), uid, args)
+
+def interactive_config(args, config, remaining_argv):
+ import readline
+
+ new_config = False
+ section = 'default'
+ backup = {}
+ modified = False
+
+ print("Welcome to the interactive calendar configuration mode")
+ print("Warning - untested code ahead, raise issues at t-calendar-cli@tobixen.no")
+ if not config or not hasattr(config, 'keys'):
+ config = {}
+ print("No valid existing configuration found")
+ new_config = True
+ if config:
+ print("The following sections have been found: ")
+ print("\n".join(config.keys()))
+ if args.config_section and args.config_section != 'default':
+ section = args.config_section
+ else:
+ ## TODO: tab completion
+ section = raw_input("Chose one of those, or a new name / no name for a new configuration section: ")
+ if section in config:
+ backup = config[section].copy()
+ print("Using section " + section)
+ else:
+ section = 'default'
+
+ if not section in config:
+ config[section] = {}
+
+ for config_key in ('caldav_url', 'caldav_user', 'caldav_pass', 'language', 'timezone'):
+ print("Config option %s - old value: %s" % (config_key, config[section].get(config_key, '(None)')))
+ value = raw_input("Enter new value (or just enter to keep the old): ")
+ if value:
+ config[section][config_key] = value
+ modified = True
+
+ if not modified:
+ print("No configuration changes have been done")
+ else:
+ options = []
+ if section:
+ options.append(('save', 'save configuration into section %s' % section))
+ if backup or not section:
+ options.append(('save_other', 'add this new configuration into a new section in the configuration file'))
+ if remaining_argv:
+ options.append(('use', 'use this configuration without saving'))
+ options.append(('abort', 'abort without saving'))
+ print("CONFIGURATION DONE ...")
+ for o in options:
+ print("Type %s if you want to %s" % o)
+ cmd = raw_input("Enter a command: ")
+ if cmd in ('save', 'save_other'):
+ if cmd == 'save_other':
+ new_section = raw_input("New config section name: ")
+ config[new_section] = config[section]
+ if backup:
+ config[section] = backup
+ else:
+ del config[section]
+ section = new_section
+ if os.path.isfile(args.config_file):
+ os.rename(args.config_file, "%s.%s.bak" % (args.config_file, int(time.time())))
+ with open(args.config_file, 'w') as outfile:
+ json.dump(config, outfile, indent=4)
+
+
+ if args.config_section == 'default' and section != 'default':
+ config['default'] = config[section]
+ return config
def calendar_add(caldav_conn, args):
cal = Calendar()
@@ -110,10 +182,31 @@ def calendar_add(caldav_conn, args):
event = Event()
## TODO: timezone
## read timestamps from arguments
- dtstart = dateutil.parser.parse(args.event_time)
+ time_units = {
+ 's': 1, 'm': 60, 'h': 3600,
+ 'd': 86400, 'w': 604800
+ }
+ event_spec = args.event_time.split('+')
+ if len(event_spec)>3:
+ raise ValueError('Invalid event time "%s" - can max contain 2 plus-signs' % event_time)
+ elif len(event_spec)==3:
+ event_time = '%s+%s' % tuple(event_spec[0:2])
+ event_duration = event_spec[2]
+ elif len(event_spec)==2 and not event_spec[1][-1:] in time_units:
+ event_time = '%s+%s' % tuple(event_spec[0:2])
+ event_duration = '1h'
+ elif len(event_spec)==2:
+ event_time = '%s' % event_spec[0]
+ event_duration = event_spec[1]
+ else:
+ event_time = event_spec[0]
+ event_duration = '1h'
+ ## TODO: error handling
+ event_duration_secs = int(event_duration[:-1]) * time_units[event_duration[-1:]]
+ dtstart = dateutil.parser.parse(event_spec[0])
event.add('dtstart', dtstart)
## TODO: handle duration and end-time as options. default 3600s by now.
- event.add('dtend', dtstart + timedelta(0,3600))
+ event.add('dtend', dtstart + timedelta(0,event_duration_secs))
## not really correct, and it breaks i.e. with google calendar
#event.add('dtstamp', datetime.now())
## maybe we should generate some uid?
@@ -171,7 +264,7 @@ def calendar_agenda(caldav_conn, args):
events = []
if args.icalendar:
for ical in events_:
- print ical.data
+ print(ical.data)
else:
## flatten. A recurring event may be a list of events.
for event_cal in events_:
@@ -215,9 +308,12 @@ def main():
help="Specify config file", metavar="FILE", default=os.getenv('XDG_CONFIG_HOME', os.getenv('HOME', '~') + '/.config')+'/calendar.conf')
conf_parser.add_argument("--config-section",
help="Specify config section; allows several caldav servers to be configured in the same config file", default='default')
+ conf_parser.add_argument("--interactive-config",
+ help="Interactively ask for configuration", action="store_true")
args, remaining_argv = conf_parser.parse_known_args()
config = {}
+
try:
with open(args.config_file) as config_file:
config = json.load(config_file)
@@ -225,10 +321,17 @@ def main():
## File not found
logging.info("no config file found")
except ValueError:
- logging.error("error in config file", exc_info=True)
- raise
+ if args.interactive_config:
+ logging.error("error in config file. Be aware that the current config file will be ignored and overwritten", exc_info=True)
+ else:
+ logging.error("error in config file. You may want to run --interactive-config or fix the config file", exc_info=True)
- defaults = config.get(args.config_section, {})
+ if args.interactive_config:
+ config = interactive_config(args, config, remaining_argv)
+ if not remaining_argv:
+ return
+ else:
+ defaults = config.get(args.config_section, {})
# Parse rest of arguments
# Don't suppress add_help here so it will handle -h