# HG changeset patch # User Paul Boddie # Date 1485815291 -3600 # Node ID 7fe3be7f0ead98a7649c2b808e8b127ee6cb0de7 # Parent 0453273cccecbf50b7da225224958f190ce6e328 Changed the config module to load and interpret the configuration file content, exposing the settings as a dictionary instead of as module attributes. diff -r 0453273cccec -r 7fe3be7f0ead imiptools/config.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/imiptools/config.py Mon Jan 30 23:28:11 2017 +0100 @@ -0,0 +1,73 @@ +#!/usr/bin/env python + +""" +Configuration management. + +Copyright (C) 2017 Paul Boddie + +This program is free software; you can redistribute it and/or modify it under +the terms of the GNU General Public License as published by the Free Software +Foundation; either version 3 of the License, or (at your option) any later +version. + +This program is distributed in the hope that it will be useful, but WITHOUT +ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS +FOR A PARTICULAR PURPOSE. See the GNU General Public License for more +details. + +You should have received a copy of the GNU General Public License along with +this program. If not, see . +""" + +from compiler import parseFile +from os.path import isfile, join, split +from compiler.ast import Assign, AssName, Const, Discard, Module, Name, Stmt + +config_path = [".", "/etc/imip-agent", split(__file__)[0]] + +builtins = { + "False" : False, + "None" : None, + "True" : True, + } + +def get_config(filename="config.txt", path=config_path): + + "Obtain the configuration from 'filename', searching 'path' for the file." + + for dirname in path: + pathname = join(dirname, filename) + if isfile(pathname): + module = parseFile(pathname) + break + else: + return {} + + return get_config_data(module, {}) + +def get_config_data(module, d): + + "Interpret the parsed 'module', storing mappings in 'd'." + + name = None + + for node in module.getChildNodes(): + if isinstance(node, (Module, Stmt)): + get_config_data(node, d) + elif isinstance(node, Discard): + pass + elif isinstance(node, Assign): + if len(node.nodes) == 1 and isinstance(node.nodes[0], AssName): + name = node.nodes[0].name + if isinstance(node.expr, Const): + d[name] = node.expr.value + elif isinstance(node.expr, Name): + d[name] = d.get(node.expr.name, builtins.get(node.expr.name)) + + return d + +# Expose settings via a module-level name. + +settings = get_config() + +# vim: tabstop=4 expandtab shiftwidth=4 diff -r 0453273cccec -r 7fe3be7f0ead imiptools/config.txt --- a/imiptools/config.txt Mon Jan 30 23:23:30 2017 +0100 +++ b/imiptools/config.txt Mon Jan 30 23:28:11 2017 +0100 @@ -1,7 +1,3 @@ -#!/usr/bin/env python - -"Configuration settings for imiptools programs." - # The public identity of the agent. MESSAGE_SENDER = "calendar@example.com" @@ -138,5 +134,3 @@ # length is used (which should be 76 characters). CALENDAR_LINE_LENGTH = None - -# vim: tabstop=4 expandtab shiftwidth=4 diff -r 0453273cccec -r 7fe3be7f0ead imiptools/content.py --- a/imiptools/content.py Mon Jan 30 23:23:30 2017 +0100 +++ b/imiptools/content.py Mon Jan 30 23:28:11 2017 +0100 @@ -3,7 +3,7 @@ """ The handler invocation mechanism. -Copyright (C) 2014, 2015 Paul Boddie +Copyright (C) 2014, 2015, 2017 Paul Boddie This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software @@ -19,7 +19,7 @@ this program. If not, see . """ -from imiptools.config import IMIP_COUNTER_AS_REQUEST +from imiptools.config import settings from imiptools.data import Object, parse_object, get_value try: @@ -27,6 +27,8 @@ except ImportError: from StringIO import StringIO +IMIP_COUNTER_AS_REQUEST = settings["IMIP_COUNTER_AS_REQUEST"] + def handle_itip_part(part, handlers): """ diff -r 0453273cccec -r 7fe3be7f0ead imiptools/filesys.py --- a/imiptools/filesys.py Mon Jan 30 23:23:30 2017 +0100 +++ b/imiptools/filesys.py Mon Jan 30 23:28:11 2017 +0100 @@ -3,7 +3,7 @@ """ Filesystem utilities. -Copyright (C) 2014, 2015 Paul Boddie +Copyright (C) 2014, 2015, 2017 Paul Boddie This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software @@ -20,11 +20,14 @@ """ import errno -from imiptools.config import DEFAULT_PERMISSIONS, DEFAULT_DIR_PERMISSIONS +from imiptools.config import settings from os.path import abspath, commonprefix, exists, join, split from os import chmod, getpid, makedirs, mkdir, rename, rmdir from time import sleep, time +DEFAULT_PERMISSIONS = settings["DEFAULT_PERMISSIONS"] +DEFAULT_DIR_PERMISSIONS = settings["DEFAULT_DIR_PERMISSIONS"] + def check_dir(base, filename): "Return whether 'base' contains 'filename'." diff -r 0453273cccec -r 7fe3be7f0ead imiptools/handlers/__init__.py --- a/imiptools/handlers/__init__.py Mon Jan 30 23:23:30 2017 +0100 +++ b/imiptools/handlers/__init__.py Mon Jan 30 23:28:11 2017 +0100 @@ -3,7 +3,7 @@ """ General handler support for incoming calendar objects. -Copyright (C) 2014, 2015, 2016 Paul Boddie +Copyright (C) 2014, 2015, 2016, 2017 Paul Boddie This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software @@ -21,11 +21,15 @@ from email.mime.text import MIMEText from imiptools.client import ClientForObject -from imiptools.config import MANAGER_PATH, MANAGER_URL, MANAGER_URL_SCHEME +from imiptools.config import settings from imiptools.data import check_delegation, get_address, get_uri, \ get_sender_identities, uri_dict, uri_item from socket import gethostname +MANAGER_PATH = settings["MANAGER_PATH"] +MANAGER_URL = settings["MANAGER_URL"] +MANAGER_URL_SCHEME = settings["MANAGER_URL_SCHEME"] + # References to the Web interface. def get_manager_url(): diff -r 0453273cccec -r 7fe3be7f0ead imiptools/i18n.py --- a/imiptools/i18n.py Mon Jan 30 23:23:30 2017 +0100 +++ b/imiptools/i18n.py Mon Jan 30 23:28:11 2017 +0100 @@ -3,7 +3,7 @@ """ Internationalisation support. -Copyright (C) 2015 Paul Boddie +Copyright (C) 2015, 2017 Paul Boddie This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software @@ -19,10 +19,13 @@ this program. If not, see . """ -from imiptools.config import LOCALE_DIR, TRANS_DOMAIN +from imiptools.config import settings from os.path import abspath, exists, join, split import gettext +LOCALE_DIR = settings["LOCALE_DIR"] +TRANS_DOMAIN = settings["TRANS_DOMAIN"] + def get_locale_dir(): locale_dir = abspath(join(split(__file__)[0], "..", "locale")) if exists(locale_dir): diff -r 0453273cccec -r 7fe3be7f0ead imiptools/mail.py --- a/imiptools/mail.py Mon Jan 30 23:23:30 2017 +0100 +++ b/imiptools/mail.py Mon Jan 30 23:28:11 2017 +0100 @@ -3,7 +3,7 @@ """ Mail preparation support. -Copyright (C) 2014, 2015, 2016 Paul Boddie +Copyright (C) 2014, 2015, 2016, 2017 Paul Boddie This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software @@ -19,12 +19,16 @@ this program. If not, see . """ -from imiptools.config import LOCAL_PREFIX, MESSAGE_SENDER, OUTGOING_PREFIX +from imiptools.config import settings from email.mime.message import MIMEMessage from email.mime.multipart import MIMEMultipart from email.mime.text import MIMEText from smtplib import LMTP, SMTP +LOCAL_PREFIX = settings["LOCAL_PREFIX"] +MESSAGE_SENDER = settings["MESSAGE_SENDER"] +OUTGOING_PREFIX = settings["OUTGOING_PREFIX"] + # Fake gettext function for strings to be translated later. _ = lambda s: s diff -r 0453273cccec -r 7fe3be7f0ead imiptools/profile.py --- a/imiptools/profile.py Mon Jan 30 23:23:30 2017 +0100 +++ b/imiptools/profile.py Mon Jan 30 23:28:11 2017 +0100 @@ -3,7 +3,7 @@ """ User profile management. -Copyright (C) 2015, 2016 Paul Boddie +Copyright (C) 2015, 2016, 2017 Paul Boddie This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software @@ -19,7 +19,7 @@ this program. If not, see . """ -from imiptools import config +from imiptools.config import settings from imiptools.dates import get_default_timezone from imiptools.filesys import fix_permissions, FileBase from os.path import exists, isdir @@ -42,18 +42,18 @@ known_keys = { "CN" : "", - "LANG" : config.LANG, "TZID" : get_default_timezone(), - "add_method_response" : config.ADD_RESPONSE_DEFAULT, - "event_refreshing" : config.REFRESHING_DEFAULT, - "freebusy_bundling" : config.BUNDLING_DEFAULT, - "freebusy_messages" : config.NOTIFYING_DEFAULT, - "freebusy_offers" : config.FREEBUSY_OFFER_DEFAULT, - "freebusy_publishing" : config.PUBLISHING_DEFAULT, - "freebusy_sharing" : config.SHARING_DEFAULT, - "incoming" : config.INCOMING_DEFAULT, - "organiser_replacement" : config.ORGANISER_REPLACEMENT_DEFAULT, - "participating" : config.PARTICIPATING_DEFAULT, + "LANG" : settings["LANG"], + "add_method_response" : settings["ADD_RESPONSE_DEFAULT"], + "event_refreshing" : settings["REFRESHING_DEFAULT"], + "freebusy_bundling" : settings["BUNDLING_DEFAULT"], + "freebusy_messages" : settings["NOTIFYING_DEFAULT"], + "freebusy_offers" : settings["FREEBUSY_OFFER_DEFAULT"], + "freebusy_publishing" : settings["PUBLISHING_DEFAULT"], + "freebusy_sharing" : settings["SHARING_DEFAULT"], + "incoming" : settings["INCOMING_DEFAULT"], + "organiser_replacement" : settings["ORGANISER_REPLACEMENT_DEFAULT"], + "participating" : settings["PARTICIPATING_DEFAULT"], "permitted_times" : None, } @@ -103,7 +103,7 @@ } def __init__(self, user, store_dir=None): - FileBase.__init__(self, store_dir or config.PREFERENCES_DIR) + FileBase.__init__(self, store_dir or settings["PREFERENCES_DIR"]) self.user = user def get(self, name, default=None, config_default=False): diff -r 0453273cccec -r 7fe3be7f0ead imiptools/stores/database/postgresql.py --- a/imiptools/stores/database/postgresql.py Mon Jan 30 23:23:30 2017 +0100 +++ b/imiptools/stores/database/postgresql.py Mon Jan 30 23:28:11 2017 +0100 @@ -3,7 +3,7 @@ """ A PostgreSQL database store of calendar data. -Copyright (C) 2016 Paul Boddie +Copyright (C) 2016, 2017 Paul Boddie This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software @@ -19,10 +19,13 @@ this program. If not, see . """ -from imiptools.config import STORE_DIR, JOURNAL_DIR +from imiptools.config import settings from imiptools.stores.database.common import DatabaseStore, DatabaseJournal import psycopg2 +STORE_DIR = settings["STORE_DIR"] +JOURNAL_DIR = settings["JOURNAL_DIR"] + class Store(DatabaseStore): "A PostgreSQL database store of calendar objects and free/busy data." diff -r 0453273cccec -r 7fe3be7f0ead imiptools/stores/file.py --- a/imiptools/stores/file.py Mon Jan 30 23:23:30 2017 +0100 +++ b/imiptools/stores/file.py Mon Jan 30 23:28:11 2017 +0100 @@ -3,7 +3,7 @@ """ A simple filesystem-based store of calendar data. -Copyright (C) 2014, 2015, 2016 Paul Boddie +Copyright (C) 2014, 2015, 2016, 2017 Paul Boddie This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software @@ -22,7 +22,7 @@ from imiptools.stores.common import StoreBase, PublisherBase, JournalBase from datetime import datetime -from imiptools.config import STORE_DIR, PUBLISH_DIR, JOURNAL_DIR +from imiptools.config import settings from imiptools.data import make_calendar, parse_object, to_stream from imiptools.dates import format_datetime, get_datetime, to_timezone from imiptools.filesys import fix_permissions, FileBase @@ -34,6 +34,10 @@ from os import listdir, remove, rmdir import codecs +STORE_DIR = settings["STORE_DIR"] +PUBLISH_DIR = settings["PUBLISH_DIR"] +JOURNAL_DIR = settings["JOURNAL_DIR"] + class FileStoreBase(FileBase): "A file store supporting user-specific locking and tabular data." diff -r 0453273cccec -r 7fe3be7f0ead tools/install.sh --- a/tools/install.sh Mon Jan 30 23:23:30 2017 +0100 +++ b/tools/install.sh Mon Jan 30 23:28:11 2017 +0100 @@ -78,21 +78,41 @@ rm "$INSTALL_DIR/imip_store.py"* fi -# Install the config module in a more appropriate location. +# Install the configuration in a more appropriate location. # Create new versions of configuration files instead of overwriting. if [ ! -e "$CONFIG_DIR" ]; then mkdir -p "$CONFIG_DIR" fi +# Handle any old config module in the configuration location. + if [ -e "$CONFIG_DIR/config.py" ]; then - if ! cmp "$INSTALL_DIR/imiptools/config.py" "$CONFIG_DIR/config.py" > /dev/null 2>&1 ; then - mv "$INSTALL_DIR/imiptools/config.py" "$CONFIG_DIR/config.py.new" + + # Rename the old config module. + + mv "$CONFIG_DIR/config.py" "$CONFIG_DIR/config.txt" +fi + +# Handle any existing configuration file in the configuration location. + +if [ -e "$CONFIG_DIR/config.txt" ]; then + + # Install the new configuration file alongside the existing file if + # different. + + if ! cmp "$INSTALL_DIR/imiptools/config.txt" "$CONFIG_DIR/config.txt" > /dev/null 2>&1 ; then + cp "$INSTALL_DIR/imiptools/config.txt" "$CONFIG_DIR/config.txt.new" fi + +# Otherwise, just copy the configuration file. + else - mv "$INSTALL_DIR/imiptools/config.py" "$CONFIG_DIR/config.py" + cp "$INSTALL_DIR/imiptools/config.txt" "$CONFIG_DIR/config.txt" fi +# Update the tools configuration file. + if [ -e "$CONFIG_DIR/config.sh" ]; then if ! cmp "tools/config.sh" "$CONFIG_DIR/config.sh" > /dev/null 2>&1 ; then cp "tools/config.sh" "$CONFIG_DIR/config.sh.new" @@ -101,10 +121,6 @@ cp "tools/config.sh" "$CONFIG_DIR/config.sh" fi -# Replace the config module with a symbolic link. - -ln -s "$CONFIG_DIR/config.py" "$INSTALL_DIR/imiptools/config.py" - # Copy related configuration files. if [ ! -e "$CONFIG_DIR/postgresql" ]; then