changeset 266:46571485b7d4

Allow loading configuration files from directories when using the "<dir>" prefix in filenames. Unknown filetypes within these directories are ignored automatically.
author Franz Glasner <fzglas.hg@dom66.de>
date Thu, 10 Sep 2020 02:00:11 +0200
parents 39c379fa8c65
children d715c10f2930
files CHANGES.txt configmix/__init__.py
diffstat 2 files changed, 61 insertions(+), 9 deletions(-) [+]
line wrap: on
line diff
--- a/CHANGES.txt	Thu Sep 10 01:09:16 2020 +0200
+++ b/CHANGES.txt	Thu Sep 10 02:00:11 2020 +0200
@@ -13,6 +13,19 @@
 --------------
 
 .. changelog::
+   :version: n/a
+   :released: n/a
+
+   .. change::
+      :tags: feature
+
+      Allow loading configuration files from directories when using
+      the "<dir>" prefix in filenames.
+
+      Unknown filetypes within these directories are ignored
+      automatically.
+
+.. changelog::
    :version: 0.9
    :released: 2020-07-28
 
--- a/configmix/__init__.py	Thu Sep 10 01:09:16 2020 +0200
+++ b/configmix/__init__.py	Thu Sep 10 02:00:11 2020 +0200
@@ -28,6 +28,7 @@
 import fnmatch
 import copy
 import io
+import os
 import re
 
 from .compat import u, u2fs
@@ -70,9 +71,15 @@
     else:
         ex = merge(None, Configuration(defaults))
     for f in files:
-        nx = _load_cfg_from_file(f)
-        if nx is not None:
-            ex = merge(nx, ex)
+        if f.startswith("<dir>"):
+            for f2 in _get_configuration_files_from_dir(f[5:]):
+                nx = _load_cfg_from_file(f2, ignore_unknown=True)
+                if nx is not None:
+                    ex = merge(nx, ex)
+        else:
+            nx = _load_cfg_from_file(f)
+            if nx is not None:
+                ex = merge(nx, ex)
     if extras:
         ex = merge(Configuration(extras), ex)
     return Configuration(ex)
@@ -90,14 +97,40 @@
     else:
         ex = safe_merge(None, Configuration(defaults))
     for f in files:
-        nx = _load_cfg_from_file(f)
-        if nx is not None:
-            ex = safe_merge(nx, ex)
+        if f.startswith("<dir>"):
+            for f2 in _get_configuration_files_from_dir(f[5:]):
+                nx = _load_cfg_from_file(f2, ignore_unknown=True)
+                if nx is not None:
+                    ex = safe_merge(nx, ex)
+        else:
+            nx = _load_cfg_from_file(f)
+            if nx is not None:
+                ex = safe_merge(nx, ex)
     if extras:
         ex = safe_merge(Configuration(extras), ex)
     return Configuration(ex)
 
 
+def _get_configuration_files_from_dir(root):
+    """Returns the sorted list of files within directory `root`
+
+    """
+    files = []
+
+    if not os.path.isdir(root):
+        return files
+
+    dirfiles = os.listdir(root)
+    dirfiles.sort()
+    for f in dirfiles:
+        path = os.path.join(root, f)
+        if os.path.isdir(path):
+            # XXX TBD Recurse??? depth-first???
+            continue
+        files.append(path)
+    return files
+
+
 def _load_yaml(filename):
     from . import yaml
     with open(u2fs(filename), "rb") as yf:
@@ -293,10 +326,13 @@
             _extensions.insert(0, (fnpattern, mode))
 
 
-def _load_cfg_from_file(filename):
+def _load_cfg_from_file(filename, ignore_unknown=False):
     """Determine the loader for file `filename` and return the loaded
     configuration dict.
 
+    If `ignore_unknown` is `True` then unknown extensions are ignored.
+    Otherwise a :exc:`ValueError` exception is raised.
+
     Can return `None` is the file should be ignored by the caller.
 
     """
@@ -308,8 +344,11 @@
                     continue
             return mode_loaders[m](filename)
     else:
-        raise ValueError("Unknown configuration file type for filename "
-                         "%r" % filename)
+        if ignore_unknown:
+            return None
+        else:
+            raise ValueError("Unknown configuration file type for filename "
+                             "%r" % filename)
 
 
 if 0: