mutt_ldap.py: Follow the the XDG Base Directory Specification
authorW. Trevor King <wking@tremily.us>
Thu, 24 Jan 2013 23:18:33 +0000 (18:18 -0500)
committerW. Trevor King <wking@tremily.us>
Fri, 25 Jan 2013 00:13:19 +0000 (19:13 -0500)
Standards are good, especially standards for keeping a plethora of
config and data files files organized.  Use PyXDG (an optional new
dependency) to handle all of the specification logic.

The default config file is now ~/.config/mutt-ldap.cfg and the default
cache file is now ~/.cache/mutt-ldap.json.  The contents of these
files has not changed.  Without the PyXDG dependency, these defaults
are hard-coded.  With the PyXDG dependency, the defaults shift
depending on $XDG_CONFIG_HOME, $XDG_CACHE_HOME, etc.

README
mutt_ldap.py

diff --git a/README b/README
index 57e7ecc0733ce715264347f7a0684d88b7e5415d..4ba5d34468ccb1096308707d838321a24dba9c54 100644 (file)
--- a/README
+++ b/README
@@ -25,11 +25,12 @@ Dependencies
 If you're installing by hand or packaging Mutt-LDAP for another
 distribution, you'll need the following dependencies:
 
-============  ================  ===========  ======================
-Package       Purpose           Debian_      Gentoo_
-============  ================  ===========  ======================
-python-ldap_  LDAP connections  python-ldap  dev-python/python-ldap
-============  ================  ===========  ======================
+============  ====================  ===========  ======================
+Package       Purpose               Debian_      Gentoo_
+============  ====================  ===========  ======================
+python-ldap_  LDAP connections      python-ldap  dev-python/python-ldap
+PyXDG_        Optional XDG support  python-xdg   dev-python/pyxdg
+============  ====================  ===========  ======================
 
 Installing by hand
 ------------------
@@ -54,14 +55,22 @@ Add the following line to your ``~/.muttrc``::
 
 Search for addresses (from Mutt_) with ``^t``, optionally after typing
 part of the name.  Configure your connection by creating
-``~/.mutt-ldap.rc`` containing something like::
+``$XDG_CONFIG_HOME/mutt-ldap.cfg`` containing something like::
 
   [connection]
   server = myserver.example.net
   basedn = ou=people,dc=example,dc=net
 
+The query cache (enabled by default) will be created at
+``$XDG_DATA_HOME/mutt-ldap.json``, unless overriden by an explicit
+``cache.path`` setting.
+
 See the ``CONFIG`` options in ``mutt_ldap.py`` for other available
-settings.
+settings.  See the `XDG Base Directory Specification`_ for more
+details on configuration and cache file locations.  If the ``xdg``
+module supplied by PyXDG_ is not available, the default configuration
+path falls back on ``~/.config/mutt-ldap.cfg`` and the default cache
+path falls back on ``~/.cache/mutt-ldap.json``.
 
 Licence
 =======
@@ -88,7 +97,10 @@ Related work
 .. _layman: http://layman.sourceforge.net/
 .. _wtk overlay: http://blog.tremily.us/posts/Gentoo_overlay/
 .. _Debian: http://www.debian.org/
+.. _PyXDG: http://freedesktop.org/wiki/Software/pyxdg
 .. _Git: http://git-scm.com/
+.. _XDG Base Directory Specification:
+   http://standards.freedesktop.org/basedir-spec/basedir-spec-latest.html
 .. _GNU General Public License Version 3: http://www.gnu.org/licenses/gpl.html
 .. _GitHub: https://github.com/wking/mutt-ldap
 .. _GitHub issue tracker: https://github.com/wking/mutt-ldap/issues
index 103d0f75e3cb6aad557c9afdac608d78331f020e..b1ce02860566ed025bf6d645bcd4a4face1b613c 100755 (executable)
@@ -33,6 +33,12 @@ import time as _time
 import ldap as _ldap
 import ldap.sasl as _ldap_sasl
 
+_xdg_import_error = None
+try:
+    import xdg.BaseDirectory as _xdg_basedirectory
+except ImportError as _xdg_import_error:
+    _xdg_basedirectory = None
+
 
 __version__ = '0.1'
 
@@ -44,9 +50,11 @@ LOG.setLevel(_logging.ERROR)
 
 class Config (_configparser.SafeConfigParser):
     def load(self):
-        read_configfiles = self.read(_os_path.expanduser('~/.mutt-ldap.rc'))
+        config_paths = self._get_config_paths()
+        LOG.info(u'load configuration from {0}'.format(config_paths))
+        read_config_paths = self.read(config_paths)
         self._setup_defaults()
-        LOG.info(u'loaded configuration from {0}'.format(read_configfiles))
+        LOG.info(u'loaded configuration from {0}'.format(read_config_paths))
 
     def get_connection_class(self):
         if self.getboolean('cache', 'enable'):
@@ -76,6 +84,8 @@ class Config (_configparser.SafeConfigParser):
         _sys.argv = [unicode(arg, argv_encoding) for arg in _sys.argv]
 
     def _setup_cache_defaults(self):
+        if not self.get('cache', 'path'):
+            self.set('cache', 'path', self._get_cache_path())
         if not self.get('cache', 'fields'):
             # setup a reasonable default
             fields = ['mail', 'cn', 'displayName']  # used by format_entry()
@@ -84,6 +94,34 @@ class Config (_configparser.SafeConfigParser):
                 fields.append(optional_column)
             self.set('cache', 'fields', ' '.join(fields))
 
+    def _get_config_paths(self):
+        "Get configuration file paths"
+        if _xdg_basedirectory:
+            paths = list(reversed(list(
+                        _xdg_basedirectory.load_config_paths(''))))
+            if not paths:  # setup something for a useful log message
+                paths.append(_xdg_basedirectory.save_config_path(''))
+        else:
+            self._log_xdg_import_error()
+            paths = [_os_path.expanduser(_os_path.join('~', '.config'))]
+        return [_os_path.join(path, 'mutt-ldap.cfg') for path in paths]
+
+    def _get_cache_path(self):
+        "Get the cache file path"
+        if _xdg_basedirectory:
+            path = _xdg_basedirectory.save_cache_path('')
+        else:
+            self._log_xdg_import_error()
+            path = _os_path.expanduser(_os_path.join('~', '.cache'))
+        return _os_path.join(path, 'mutt-ldap.json')
+
+    def _log_xdg_import_error(self):
+        global _xdg_import_error
+        if _xdg_import_error:
+            LOG.error(u'could not import xdg.BaseDirectory')
+            LOG.error(_xdg_import_error)
+            _xdg_import_error = None
+
 
 CONFIG = Config()
 CONFIG.add_section('connection')
@@ -103,7 +141,7 @@ CONFIG.add_section('results')
 CONFIG.set('results', 'optional-column', '') # mutt can display one optional column
 CONFIG.add_section('cache')
 CONFIG.set('cache', 'enable', 'yes') # enable caching by default
-CONFIG.set('cache', 'path', '~/.mutt-ldap.cache') # cache results here
+CONFIG.set('cache', 'path', '') # cache results here, defaults to XDG
 CONFIG.set('cache', 'fields', '')  # fields to cache (if empty, setup in the main block)
 CONFIG.set('cache', 'longevity-days', '14') # TODO: cache results for 14 days by default
 CONFIG.add_section('system')