pvl.hosts.config: --hosts-include-trace to write out all included files
authorTero Marttila <tero.marttila@aalto.fi>
Tue, 03 Mar 2015 11:58:10 +0200
changeset 713 d5e2d1d9716a
parent 712 97fa1b086b36
child 714 e0a651547bd2
pvl.hosts.config: --hosts-include-trace to write out all included files
pvl/hosts/__init__.py
pvl/hosts/config.py
pvl/hosts/tests.py
--- a/pvl/hosts/__init__.py	Tue Mar 03 11:41:32 2015 +0200
+++ b/pvl/hosts/__init__.py	Tue Mar 03 11:58:10 2015 +0200
@@ -1,4 +1,4 @@
-__version__ = '0.8.0a6'
+__version__ = '0.8.0a7'
 
 from pvl.hosts.config import (
         optparser,
--- a/pvl/hosts/config.py	Tue Mar 03 11:41:32 2015 +0200
+++ b/pvl/hosts/config.py	Tue Mar 03 11:58:10 2015 +0200
@@ -22,6 +22,9 @@
 
     hosts.add_option('--hosts-include',         metavar='PATH',
             help="Optional path for hosts includes, in addition to the host config dir")
+
+    hosts.add_option('--hosts-include-trace',   metavar='FILE',
+            help="Write out all included file paths")
     
     return hosts
 
@@ -207,7 +210,7 @@
         log.info("%s: include: %s", config_path, path)
         yield path
 
-def apply_hosts_configs (options, path, name, config, parent=None, defaults={}):
+def apply_hosts_configs (options, path, name, config, parent=None, defaults={}, include_trace=None):
     """
         Load hosts from a configobj.Section (which can be the top-level ConfigObj).
 
@@ -217,6 +220,7 @@
             config          configobj.Section
             parent          parent section from included files or --hosts-domain
             defaults        hierarchial section defaults
+            include_trace   - optional list to append loaded files to
     """
     
     # items in this section
@@ -226,12 +230,15 @@
 
     # process includes?
     if 'include' in section:
-        includes = section.pop('include').split()
+        # convert from unicode
+        includes = [str(include) for include in section.pop('include').split()]
 
         includes = list(parse_config_includes(options, path, includes))
 
         # within our domain context
-        for host in apply_hosts_files(options, includes, parent=name, defaults=section):
+        for host in apply_hosts_files(options, includes, include_trace=include_trace,
+                parent=name, defaults=section
+        ):
             yield host
     else:
         includes = None
@@ -304,26 +311,38 @@
     
     return apply_hosts_configs(options, path, name, config, **opts)
 
-def apply_hosts_file (options, path, **opts):
+def apply_hosts_file (options, path, include_trace=None, **opts):
     """
         Load Hosts from a file path.
+            
+            include_trace           - optional list to append loaded files to
     """
+    
+    if include_trace is not None:
+        log.debug("%s: include trace", path)
+        include_trace.append(path)
 
     try:
         file = open(path)
     except IOError as ex:
         raise HostConfigError(path, ex.strerror)
 
-    for host in apply_hosts_config(options, file, **opts):
+    for host in apply_hosts_config(options, file, include_trace=include_trace, **opts):
         yield host
 
-def apply_hosts_directory (options, root, **opts):
+def apply_hosts_directory (options, root, include_trace=None, **opts):
     """
         Load Hosts from a directory, loading each file within the directory.
 
+            include_trace           - optional list to append loaded files to
+
         Skips .dotfiles.
     """
 
+    if include_trace is not None:
+        log.debug("%s: include trace", root)
+        include_trace.append(root)
+
     for name in sorted(os.listdir(root)):
         path = os.path.join(root, name)
 
@@ -335,7 +354,7 @@
             log.debug("%s: skip directory: %s", root, name)
             continue
 
-        for host in apply_hosts_file(options, path, **opts):
+        for host in apply_hosts_file(options, path, include_trace=include_trace, **opts):
             yield host
 
 def apply_hosts_files (options, files, **opts):
@@ -359,10 +378,16 @@
 
         Exits with status=2 if loading the confs fails.
     """
+
+    if options.hosts_include_trace:
+        log.debug("include trace")
+        include_trace = [ ]
+    else:
+        include_trace = None
     
     try:
         # load hosts from configs
-        hosts = list(apply_hosts_files(options, args))
+        hosts = list(apply_hosts_files(options, args, include_trace=include_trace))
     except HostConfigObjError as error:
         log.error("%s", error)
         log.error("\t%s", error.line_contents)
@@ -371,6 +396,11 @@
     except HostConfigError as error:
         log.error("%s", error)
         sys.exit(2)
+        
+    if options.hosts_include_trace:
+        with pvl.args.apply_file(options.hosts_include_trace, 'w') as file:
+            for include in include_trace:
+                print >>file, include
 
     # stable ordering
     return sorted(hosts, key=Host.sort_key)
--- a/pvl/hosts/tests.py	Tue Mar 03 11:41:32 2015 +0200
+++ b/pvl/hosts/tests.py	Tue Mar 03 11:58:10 2015 +0200
@@ -18,6 +18,7 @@
                 hosts_charset   = 'utf-8',
                 hosts_domain    = None,
                 hosts_include   = None,
+                hosts_include_trace = None,
         )
 
     def assertHostEqual(self, host, host_str, attrs):
@@ -185,7 +186,13 @@
 
     def testApplyIncludePath(self):
         self.options.hosts_include = 'etc/hosts'
-        self.assertHostsEqual(config.apply_hosts_files(self.options, ['etc/zones/forward/test']), [
+        include_trace = [ ]
+
+        hosts = list(config.apply_hosts_files(self.options, ['etc/zones/forward/test'],
+            include_trace   = include_trace,
+        ))
+
+        self.assertHostsEqual(hosts, [
                 ('quux@asdf.test', dict(
                     ip          = ipaddr.IPAddress('192.0.2.5'),
                 )),
@@ -197,6 +204,15 @@
                 )),
         ])
 
+        self.assertEqual(include_trace, [
+            'etc/zones/forward/test',
+            'etc/zones/forward/test/asdf.test',
+            'etc/zones/forward/test/test',
+            'etc/hosts/test.d/',
+            'etc/hosts/test.d/bar',
+            'etc/hosts/test.d/foo',
+        ])
+
     def testApply(self):
         self.assertHostsEqual(config.apply(self.options, ['etc/hosts/example.com']), [
                 ('foo@example.com', dict(