From 023cf168adffc5ac80e40f0e5e75f02a8c431750 Mon Sep 17 00:00:00 2001 From: Gustavo Sousa Date: Fri, 14 Apr 2023 10:18:20 -0300 Subject: [PATCH] alot/settings: Use notmuch config to read configuration The main benefit from this is that we get the defaults directly from notmuch and do not risk using inconsistent configuration values. A good example of this is getting the database path. Getting the path directly from the notmuch config file is not enough, because the user might be using the default location with no explicit entry in the file. Since notmuch does is a bit of logic notmuch to get the database path (see section "DATABASE LOCATION" in man page for notmuch-config(1)), it is better to get it directly from "notmuch config". Since get_notmuch_setting() now always returns a string, also refactor the call to settings.get_notmuch_setting('maildir', 'synchronize_flags') for this new reality. --- alot/db/manager.py | 2 +- alot/defaults/notmuch.rc | 3 --- alot/defaults/notmuch.rc.spec | 3 --- alot/settings/manager.py | 12 +++++++----- alot/settings/utils.py | 35 +++++++++++++++++++++++++++++++++++ setup.py | 1 - 6 files changed, 43 insertions(+), 13 deletions(-) delete mode 100644 alot/defaults/notmuch.rc delete mode 100644 alot/defaults/notmuch.rc.spec diff --git a/alot/db/manager.py b/alot/db/manager.py index 8af6a9472..6d950ef74 100644 --- a/alot/db/manager.py +++ b/alot/db/manager.py @@ -72,7 +72,7 @@ def flush(self): raise DatabaseROError() if self.writequeue: # read notmuch's config regarding imap flag synchronization - sync = settings.get_notmuch_setting('maildir', 'synchronize_flags') + sync = settings.get_notmuch_setting('maildir', 'synchronize_flags') == 'true' # go through writequeue entries while self.writequeue: diff --git a/alot/defaults/notmuch.rc b/alot/defaults/notmuch.rc deleted file mode 100644 index f03fcda1e..000000000 --- a/alot/defaults/notmuch.rc +++ /dev/null @@ -1,3 +0,0 @@ -[maildir] -synchronize_flags = False - diff --git a/alot/defaults/notmuch.rc.spec b/alot/defaults/notmuch.rc.spec deleted file mode 100644 index fb94ffd04..000000000 --- a/alot/defaults/notmuch.rc.spec +++ /dev/null @@ -1,3 +0,0 @@ -[maildir] -synchronize_flags = boolean(default=False) - diff --git a/alot/settings/manager.py b/alot/settings/manager.py index 1361384ba..4f1e39227 100644 --- a/alot/settings/manager.py +++ b/alot/settings/manager.py @@ -17,7 +17,7 @@ from ..utils import configobj as checks from .errors import ConfigError, NoMatchingAccount -from .utils import read_config +from .utils import read_config, read_notmuch_config from .utils import resolve_att from .theme import Theme @@ -36,12 +36,13 @@ def __init__(self): self._accounts = None self._accountmap = None self._notmuchconfig = None + self._notmuchconfig_path = None self._config = ConfigObj() self._bindings = None def reload(self): """Reload notmuch and alot config files""" - self.read_notmuch_config(self._notmuchconfig.filename) + self.read_notmuch_config(self._notmuchconfig_path) self.read_config(self._config.filename) def read_notmuch_config(self, path): @@ -50,8 +51,8 @@ def read_notmuch_config(self, path): :param path: path to notmuch's config file :type path: str """ - spec = os.path.join(DEFAULTSPATH, 'notmuch.rc.spec') - self._notmuchconfig = read_config(path, spec) + self._notmuchconfig = read_notmuch_config(path) + self._notmuchconfig_path = path # Set the path *after* succesful read. def _update_bindings(self, newbindings): assert isinstance(newbindings, Section) @@ -275,7 +276,8 @@ def get_notmuch_setting(self, section, key, fallback=None): :type key: str :param fallback: fallback returned if key is not present :type fallback: str - :returns: config value with type as specified in the spec-file + :returns: the config value + :rtype: str """ value = None if section in self._notmuchconfig: diff --git a/alot/settings/utils.py b/alot/settings/utils.py index 65942aff6..7b106b122 100644 --- a/alot/settings/utils.py +++ b/alot/settings/utils.py @@ -9,6 +9,7 @@ from urwid import AttrSpec from .errors import ConfigError +from ..helper import call_cmd def read_config(configpath=None, specpath=None, checks=None, @@ -82,6 +83,40 @@ def read_config(configpath=None, specpath=None, checks=None, return config +def read_notmuch_config(path): + """ + Read notmuch configuration. + + This function calls the command "notmuch --config {path} config list" and + parses its output into a ``config`` dictionary, which is then returned. + + The configuration value for a key under a section can be accessed with + ``config[section][key]``. + + The returned value is a dict ``config`` with + + :param path: path to the configuration file, which is passed as + argument to the --config option of notmuch. + :type path: str + :raises: :class:`~alot.settings.errors.ConfigError` + :rtype: `dict` + """ + cmd = ['notmuch', '--config', path, 'config', 'list'] + out, err, code = call_cmd(cmd) + if code != 0: + msg = f'failed to read notmuch config with command {cmd} (exit error: {code}):\n{err}' + logging.error(msg) + raise ConfigError(msg) + + config = {} + for line in out.splitlines(): + left_hand, right_hand = line.split("=", maxsplit=1) + section, key = left_hand.split(".", maxsplit=1) + config.setdefault(section, {})[key] = right_hand + + return config + + def resolve_att(a, fallback): """ replace '' and 'default' by fallback values """ if a is None: diff --git a/setup.py b/setup.py index d98e6c9d0..21416affd 100755 --- a/setup.py +++ b/setup.py @@ -31,7 +31,6 @@ package_data={ 'alot': [ 'defaults/alot.rc.spec', - 'defaults/notmuch.rc.spec', 'defaults/abook_contacts.spec', 'defaults/default.theme', 'defaults/default.bindings',