1+ import io
12import shutil
23from copy import copy
34from io import BytesIO , TextIOWrapper
67from os .path import exists
78import struct
89import sys
10+ from typing import Union
911
1012from configobj import ConfigObj , ConfigObjError
1113from cryptography .hazmat .primitives .ciphers import Cipher , algorithms , modes
@@ -59,23 +61,34 @@ def read_config_file(f, list_values=True):
5961 return config
6062
6163
62- def get_included_configs (config_path ) -> list :
64+ def get_included_configs (config_file : Union [ str , io . TextIOWrapper ] ) -> list :
6365 """Get a list of configuration files that are included into config_path
64- with !includedir directive."""
65- if not os .path .exists (config_path ):
66+ with !includedir directive.
67+
68+ "Normal" configs should be passed as file paths. The only exception
69+ is .mylogin which is decoded into a stream. However, it never
70+ contains include directives and so will be ignored by this
71+ function.
72+
73+ """
74+ if not isinstance (config_file , str ) or not os .path .isfile (config_file ):
6675 return []
6776 included_configs = []
68- with open (config_path ) as f :
69- include_directives = filter (
70- lambda s : s .startswith ('!includedir' ),
71- f
72- )
73- dirs = map (lambda s : s .strip ().split ()[- 1 ], include_directives )
74- dirs = filter (os .path .isdir , dirs )
75- for dir in dirs :
76- for filename in os .listdir (dir ):
77- if filename .endswith ('.cnf' ):
78- included_configs .append (os .path .join (dir , filename ))
77+
78+ try :
79+ with open (config_file ) as f :
80+ include_directives = filter (
81+ lambda s : s .startswith ('!includedir' ),
82+ f
83+ )
84+ dirs = map (lambda s : s .strip ().split ()[- 1 ], include_directives )
85+ dirs = filter (os .path .isdir , dirs )
86+ for dir in dirs :
87+ for filename in os .listdir (dir ):
88+ if filename .endswith ('.cnf' ):
89+ included_configs .append (os .path .join (dir , filename ))
90+ except (PermissionError , UnicodeDecodeError ):
91+ pass
7992 return included_configs
8093
8194
@@ -86,8 +99,12 @@ def read_config_files(files, list_values=True):
8699 _files = copy (files )
87100 while _files :
88101 _file = _files .pop (0 )
89- _files = get_included_configs (_file ) + _files
90102 _config = read_config_file (_file , list_values = list_values )
103+
104+ # expand includes only if we were able to parse config
105+ # (otherwise we'll just encounter the same errors again)
106+ if config is not None :
107+ _files = get_included_configs (_file ) + _files
91108 if bool (_config ) is True :
92109 config .merge (_config )
93110 config .filename = _config .filename
0 commit comments