U
    M8c&                     @   sn   d dl Z d dlZd dlZd dlZd dlZd dlZdd Zdd Zdd Z	dd	d
Z
dd Zdd Zdd ZdS )    Nc               	   G   sr   g }g }| D ]H}zt |}W n tjjk
r8   Y qY nX ||d || qt|}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)	filenamesZconfigsr   filenameZloadedZmerged_configZmerged_profiles r   9/tmp/pip-unpacked-wheel-ozje0y8b/botocore/configloader.pymulti_file_load_config   s    0
r   c                 C   s4   i }| D ]&}|  D ]\}}||kr|||< qq|S )N)items)Zlist_of_dictsZmerged_dictsZsingle_dictkeyvaluer   r   r   r	   V   s    r	   c                 C   s   t | }t|S )a  Parse a INI config with profiles.

    This will parse an INI config file and map top level profiles
    into a top level "profile" key.

    If you want to parse an INI file and map all section names to
    top level keys, use ``raw_config_parse`` instead.

    )raw_config_parsebuild_profile_map)config_filenameparsedr   r   r   r   _   s    
r   Tc           	      C   s<  i }| }|dk	r8t j|}t j|}t j|sHtjjt|dt	
 }z||g W n> t	jtfk
r } ztjjt||ddW 5 d}~X Y nX | D ]}i ||< ||D ]v}|||}|r(|dr(zt|}W n: tk
r& } ztjjt||ddW 5 d}~X Y nX ||| |< qq|S )a  Returns the parsed INI config contents.

    Each section name is a top level key.

    :param config_filename: The name of the INI file to parse

    :param parse_subsections: If True, parse indented blocks as
       subsections that represent their own configuration dictionary.
       For example, if the config file had the contents::

           s3 =
              signature_version = s3v4
              addressing_style = path

        The resulting ``raw_config_parse`` would be::

            {'s3': {'signature_version': 's3v4', 'addressing_style': 'path'}}

       If False, do not try to parse subsections and return the indented
       block as its literal value::

            {'s3': '
signature_version = s3v4
addressing_style = path'}

    :returns: A dict with keys for each profile found in the config
        file and the value of each key being a dict containing name
        value pairs found in that profile.

    :raises: ConfigNotFound, ConfigParseError
    N)path)r   error
)osr   
expandvars
expanduserisfiler   r   r   _unicode_pathconfigparserRawConfigParserreadErrorUnicodeDecodeErrorZConfigParseErrorsectionsoptionsget
startswith_parse_nested
ValueError)	r   Zparse_subsectionsconfigr   cpesectionoptionconfig_valuer   r   r   r   m   sB    
  r   c                 C   s2   t | tr| S t }|d kr&t }| |dS )Nreplace)
isinstancestrsysgetfilesystemencodinggetdefaultencodingdecode)r   Zfilesystem_encodingr   r   r   r      s    
r   c                 C   sD   i }|   D ]2}| }|sq|dd\}}| || < q|S )N=   )
splitlinesstripsplit)r.   r   liner   r   r   r   r   r'      s    r'   c              	   C   s   t | }i }i }i }| D ]\}}|drrzt|}W n tk
rV   Y qY nX t|dkr|||d < q|drzt|}W n tk
r   Y qY nX t|dkr|||d < q|dkr|||< q|||< q||d< ||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.

    Zprofile   r7   zsso-sessiondefaultr   sso_sessions)copydeepcopyr   r&   shlexr:   r(   len)Zparsed_ini_configZparsed_configr   r>   Zfinal_configr   valuespartsr   r   r   r      s2    3






r   )T)r   r?   r   rA   r2   Zbotocore.exceptionsr   r   r	   r   r   r   r'   r   r   r   r   r   <module>   s   ?	
?