Browse Source

Write configuration to XDG_CONFIG_HOME

 on Windows write config to APPDATA

 This probably breaks some tests, as we still don't change the
 location of the DB

 This is a partial fix for #23
Oz N Tiram 7 years ago
parent
commit
c5eec09772
3 changed files with 106 additions and 12 deletions
  1. 1 4
      pwman/__init__.py
  2. 59 3
      pwman/util/config.py
  3. 46 5
      tests/test_config.py

+ 1 - 4
pwman/__init__.py

@@ -70,9 +70,6 @@ except IOError as E:
     website = 'http://pwman3.github.io/pwman3/'
 
 
-config_dir = os.path.expanduser("~/.pwman")
-
-
 def parser_options(formatter_class=argparse.HelpFormatter):  # pragma: no cover
     parser = argparse.ArgumentParser(prog='pwman3',
                                      description=description,
@@ -94,7 +91,7 @@ def parser_options(formatter_class=argparse.HelpFormatter):  # pragma: no cover
 
 
 def get_conf(args):
-    config_dir = os.path.expanduser("~/.pwman")
+    config_dir = config.find_config_dir('pwman')
 
     if not os.path.isdir(config_dir):  # pragma: no cover
         os.mkdir(config_dir)

+ 59 - 3
pwman/util/config.py

@@ -14,12 +14,15 @@
 # along with Pwman3; if not, write to the Free Software
 # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 # ============================================================================
-# Copyright (C) 2012 Oz Nahum <nahumoz@gmail.com>
+# Copyright (C) 2018 Oz N Tiram <nahumoz@gmail.com>
 # ============================================================================
 # Copyright (C) 2006 Ivan Kelly <ivan@ivankelly.net>
 # ============================================================================
-import sys
 import os
+import platform
+import sys
+from functools import lru_cache
+
 
 if sys.version_info.major > 2:  # pragma: no cover
     from configparser import (ConfigParser, ParsingError, NoOptionError,
@@ -28,7 +31,60 @@ else:                           # pragma: no cover
     from ConfigParser import (ConfigParser, ParsingError, NoOptionError,
                               NoSectionError, MissingSectionHeaderError)
 
-config_dir = os.path.expanduser("~/.pwman")
+# XDG code taken from xdg.py
+# https://github.com/srstevenson/xdg/blob/master/xdg.py
+# Copyright © 2016-2018 Scott Stevenson <scott@stevenson.io>
+
+
+def _getenv(variable: str, default: str) -> str:
+    """Get an environment variable.
+    Parameters
+    ----------
+    variable : str
+        The environment variable.
+    default : str
+        A default value that will be returned if the environment
+        variable is unset or empty.
+    Returns
+    -------
+    str
+        The value of the environment variable, or the default value.
+    """
+    return os.environ.get(variable) or default
+
+
+XDG_CACHE_HOME = _getenv('XDG_CACHE_HOME',
+                         os.path.expandvars(os.path.join('$HOME', '.cache')))
+XDG_CONFIG_DIRS = _getenv('XDG_CONFIG_DIRS', '/etc/xdg').split(':')
+XDG_CONFIG_HOME = _getenv('XDG_CONFIG_HOME',
+                          os.path.expandvars(os.path.join('$HOME', '.config')))
+XDG_DATA_DIRS = _getenv('XDG_DATA_DIRS',
+                        '/usr/local/share/:/usr/share/').split(':')
+XDG_DATA_HOME = _getenv('XDG_DATA_HOME',
+                        os.path.expandvars(
+                            os.path.join('$HOME', '.local', 'share')))
+XDG_RUNTIME_DIR = os.getenv('XDG_RUNTIME_DIR')
+
+
+@lru_cache(maxsize=None)
+def find_config_dir(appname):
+    """
+    Backward compatibly config dir finder
+
+    If ~/.appname is not found define a new XDG compat one
+    """
+    config_dir = os.path.expanduser("~/.%s" % appname)
+
+    if os.path.exists(config_dir):
+        return config_dir
+    elif platform.system() == 'Windows':
+        return os.path.expandvars(os.path.join('$APPDATA', appname))
+    else:
+        return os.path.join(XDG_CONFIG_HOME, appname)
+
+
+config_dir = find_config_dir('pwman')
+
 
 default_config = {'Global': {'umask': '0100', 'colors': 'yes',
                              'cls_timeout': '10', 'cp_timeout': '5',

+ 46 - 5
tests/test_config.py

@@ -20,6 +20,7 @@
 import os
 import sys
 import unittest
+import unittest.mock
 from pwman.util import config
 
 
@@ -41,6 +42,50 @@ type = SQLite
 """)
 
 
+class TestFindConfigWindows(unittest.TestCase):
+
+    def test_windows_platfrom(self):
+
+        with unittest.mock.patch('platform.system') as pl:
+            pl.return_value = 'Windows'
+            os.environ['APPDATA'] = 'balls'
+            cdir = config.find_config_dir('zzzz')
+
+            self.assertEqual(
+                os.path.expandvars(os.path.join('$APPDATA', 'zzzz')),
+                cdir)
+
+
+class TestFindConfigCompat(unittest.TestCase):
+
+    c_path = os.path.expanduser("~/.zzzz_compat_posix")
+
+    def setUp(self):
+        if not os.path.exists(self.c_path):
+            os.mkdir(self.c_path)
+
+    def tearDown(self):
+        os.rmdir(self.c_path)
+
+    def test_compat(self):
+        cdir = config.find_config_dir('zzzz_compat_posix')
+        self.assertEqual(self.c_path, cdir)
+
+
+class TestFindConfigXDG(unittest.TestCase):
+
+    c_path = os.path.expanduser("~/.zzzz_posix")
+
+    def setUp(self):
+        if os.path.exists(self.c_path):
+            os.rmdir(self.c_path)
+
+    def test_new_scheme(self):
+        # assert we get xdg_fine with Linux
+        cdir = config.find_config_dir('zzzz_posix')
+        self.assertEqual(cdir, os.path.expanduser("~/.config/zzzz_posix"))
+
+
 class TestConfig(unittest.TestCase):
 
     @classmethod
@@ -59,13 +104,9 @@ class TestConfig(unittest.TestCase):
     def test_has_defaults(self):
         self.assertTrue(self.conf.parser.has_section('Readline'))
 
-    #def test_has_blowfish(self):
-    #    self.assertEqual('Blowfish', self.conf.get_value('Encryption',
-    #                                                     'algorithm'))
-
     def test_has_user_history(self):
         path = os.path.expanduser(os.path.join("~/.pwman", "history"))
-        config =self.conf.get_value('Readline', 'history')
+        config = self.conf.get_value('Readline', 'history')
         self.assertEqual(path, config)
 
     def test_has_user_db(self):