B -<`l%ã@srddlZddlZddlZddlZddlmZddlZdd„Zdd„Z dd„Z dd d „Z d d „Z dd„Z dd„ZdS)éN)Úsixc Gstg}g}xN|D]F}y t|ƒ}Wntjjk r8wYnX| | d¡¡| |¡qWt|ƒ}t|ƒ}||d<|S)a Load and combine multiple INI configs with profiles. This function will take a list of filesnames and return a single dictionary that represents the merging of the loaded config files. If any of the provided filenames does not exist, then that file is ignored. It is therefore ok to provide a list of filenames, some of which may not exist. Configuration files are **not** deep merged, only the top level keys are merged. The filenames should be passed in order of precedence. The first config file has precedence over the second config file, which has precedence over the third config file, etc. The only exception to this is that the "profiles" key is merged to combine profiles from multiple config files into a single profiles mapping. However, if a profile is defined in multiple config files, then the config file with the highest precedence is used. Profile values themselves are not merged. For example:: FileA FileB FileC [foo] [foo] [bar] a=1 a=2 a=3 b=2 [bar] [baz] [profile a] a=2 a=3 region=e [profile a] [profile b] [profile c] region=c region=d region=f The final result of ``multi_file_load_config(FileA, FileB, FileC)`` would be:: {"foo": {"a": 1}, "bar": {"a": 2}, "baz": {"a": 3}, "profiles": {"a": {"region": "c"}}, {"b": {"region": d"}}, {"c": {"region": "f"}}} Note that the "foo" key comes from A, even though it's defined in both FileA and FileB. Because "foo" was defined in FileA first, then the values for "foo" from FileA are used and the values for "foo" from FileB are ignored. Also note where the profiles originate from. Profile "a" comes FileA, profile "b" comes from FileB, and profile "c" comes from FileC. Úprofiles)Ú load_configÚbotocoreÚ exceptionsÚConfigNotFoundÚappendÚpopÚ_merge_list_of_dicts)Ú filenamesZconfigsrÚfilenameZloadedZ merged_configZmerged_profiles©r ú| ¡D]2}| ¡}|s q| dd¡\}}| ¡|| ¡<qW|S)Nú=é)Ú splitlinesÚstripÚsplit)r.rÚlinerrr r rr(¶sr(c Cs˜t |¡}i}i}xx| ¡D]l\}}| d¡rnyt |¡}Wntk rRwYnXt|ƒdkrˆ|||d<q|dkr€|||<q|||<qW||d<|S)a÷Convert the parsed INI config into a profile map. The config file format requires that every profile except the default to be prepended with "profile", e.g.:: [profile test] aws_... = foo aws_... = bar [profile bar] aws_... = foo aws_... = bar # This is *not* a profile [preview] otherstuff = 1 # Neither is this [foobar] morestuff = 2 The build_profile_map will take a parsed INI config file where each top level key represents a section name, and convert into a format where all the profiles are under a single top level "profiles" key, and each key in the sub dictionary is a profile name. For example, the above config file would be converted from:: {"profile test": {"aws_...": "foo", "aws...": "bar"}, "profile bar": {"aws...": "foo", "aws...": "bar"}, "preview": {"otherstuff": ...}, "foobar": {"morestuff": ...}, } into:: {"profiles": {"test": {"aws_...": "foo", "aws...": "bar"}, "bar": {"aws...": "foo", "aws...": "bar"}, "preview": {"otherstuff": ...}, "foobar": {"morestuff": ...}, } If there are no profiles in the provided parsed INI contents, then an empty dict will be the value associated with the ``profiles`` key. .. note:: This will not mutate the passed in parsed_ini_config. Instead it will make a deepcopy and return that value. Zprofileér7Údefaultr)ÚcopyÚdeepcopyrr'Úshlexr:r)Úlen)Zparsed_ini_configZ parsed_configrZ final_configrÚvaluesÚpartsr r rrÊs 3     r)T)rr@r>r2Zbotocore.compatrZbotocore.exceptionsrrr rrrr(rr r r rÚs ?  =