1818# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
1919# SOFTWARE.
2020
21+ import codecs
2122import logging
2223import os
2324import re
@@ -41,6 +42,7 @@ def __init__(self, caller_options):
4142 self .options = options = {
4243 # these are in alphabetical order! Always add new ones that way!
4344 'delete_strays' : False ,
45+ 'config_file_encoding' : 'ascii' ,
4446 'directory_connector_module_name' : None ,
4547 'directory_connector_overridden_options' : None ,
4648 'directory_group_filter' : None ,
@@ -56,14 +58,15 @@ def __init__(self, caller_options):
5658 'update_user_info' : True ,
5759 'username_filter_regex' : None ,
5860 }
59- options .update (caller_options )
60-
61+ options .update (caller_options )
6162 main_config_filename = options .get ('main_config_filename' )
63+ config_encoding = options ['config_file_encoding' ]
64+ try :
65+ codecs .lookup (config_encoding )
66+ except LookupError :
67+ raise AssertionException ("Unknown encoding '%s' specified with --config-file-encoding" % config_encoding )
68+ ConfigFileLoader .config_encoding = config_encoding
6269 main_config_content = ConfigFileLoader .load_root_config (main_config_filename )
63-
64- if (not os .path .isfile (main_config_filename )):
65- raise AssertionException ('Config file does not exist: %s' % (main_config_filename ))
66-
6770 self .logger = logger = logging .getLogger ('config' )
6871 logger .info ("Using main config file: %s" , main_config_filename )
6972 self .main_config = DictConfig ("<%s>" % main_config_filename , main_config_content )
@@ -606,6 +609,10 @@ class ConfigFileLoader:
606609 '''
607610 Loads config files and does pathname expansion on settings that refer to files or directories
608611 '''
612+ # config files can contain Unicode characters, so an encoding for them
613+ # can be specified as a command line argument. This defaults to ascii.
614+ config_encoding = 'ascii'
615+
609616 # key_paths in the root configuration file that should have filename values
610617 # mapped to their value options. See load_from_yaml for the option meanings.
611618 ROOT_CONFIG_PATH_KEYS = {'/adobe_users/connectors/umapi' : (True , True , None ),
@@ -680,9 +687,11 @@ def load_from_yaml(cls, filename, path_keys):
680687 cmd = filename [3 :- 1 ]
681688 try :
682689 bytes = subprocess .check_output (cmd , cwd = dir , shell = True )
683- yml = yaml .load (bytes )
690+ yml = yaml .load (bytes . decode ( cls . config_encoding , 'strict' ) )
684691 except subprocess .CalledProcessError as e :
685692 raise AssertionException ("Error executing process '%s' in dir '%s': %s" % (cmd , dir , e ))
693+ except UnicodeDecodeError as e :
694+ raise AssertionException ('Encoding error in process output: %s' % e )
686695 except yaml .error .MarkedYAMLError as e :
687696 raise AssertionException ('Error parsing process YAML data: %s' % e )
688697 else :
@@ -693,17 +702,20 @@ def load_from_yaml(cls, filename, path_keys):
693702 cls .filename = os .path .split (cls .filepath )[1 ]
694703 cls .dirpath = os .path .dirname (cls .filepath )
695704 try :
696- with open (filename , 'r' , 1 ) as input_file :
697- yml = yaml .load (input_file )
705+ with open (filename , 'rb' , 1 ) as input_file :
706+ bytes = input_file .read ()
707+ yml = yaml .load (bytes .decode (cls .config_encoding , 'strict' ))
698708 except IOError as e :
699709 # if a file operation error occurred while loading the
700- # configuration file, swallow up the exception and re-raise this
710+ # configuration file, swallow up the exception and re-raise it
701711 # as an configuration loader exception.
702- raise AssertionException ('Error reading configuration file: %s' % e )
712+ raise AssertionException ("Error reading configuration file '%s': %s" % (cls .filepath , e ))
713+ except UnicodeDecodeError as e :
714+ # as above, but in case of encoding errors
715+ raise AssertionException ("Encoding error in configuration file '%s: %s" % (cls .filepath , e ))
703716 except yaml .error .MarkedYAMLError as e :
704- # same as above, but indicate this problem has to do with
705- # parsing the configuration file.
706- raise AssertionException ('Error parsing configuration file: %s' % e )
717+ # as above, but in case of parse errors
718+ raise AssertionException ("Error parsing configuration file '%s': %s" % (cls .filepath , e ))
707719
708720 # process the content of the dict
709721 for path_key , options in path_keys .iteritems ():
0 commit comments