Completed
Pull Request — master (#917)
by
unknown
01:01
created

_fix_missing_endline_in_yaml()   A

Complexity

Conditions 3

Size

Total Lines 11

Duplication

Lines 0
Ratio 0 %

Importance

Changes 2
Bugs 1 Features 0
Metric Value
cc 3
c 2
b 1
f 0
dl 0
loc 11
rs 9.4285
1
# -*- coding: utf-8 -*-
2
3
"""
4
cookiecutter.config
5
-------------------
6
7
Global configuration handling
8
"""
9
10
from __future__ import unicode_literals
11
import copy
12
import logging
13
import os
14
import io
15
16
import poyo
17
18
from .exceptions import ConfigDoesNotExistException
19
from .exceptions import InvalidConfiguration
20
21
logger = logging.getLogger(__name__)
22
23
USER_CONFIG_PATH = os.path.expanduser('~/.cookiecutterrc')
24
25
BUILTIN_ABBREVIATIONS = {
26
    'gh': 'https://github.com/{0}.git',
27
    'bb': 'https://bitbucket.org/{0}',
28
}
29
30
DEFAULT_CONFIG = {
31
    'cookiecutters_dir': os.path.expanduser('~/.cookiecutters/'),
32
    'replay_dir': os.path.expanduser('~/.cookiecutter_replay/'),
33
    'default_context': {},
34
    'abbreviations': BUILTIN_ABBREVIATIONS,
35
}
36
37
38
def _expand_path(path):
39
    """Expand both environment variables and user home in the given path."""
40
    path = os.path.expandvars(path)
41
    path = os.path.expanduser(path)
42
    return path
43
44
45
def _fix_missing_endline_in_yaml(yaml_lines):
46
    """
47
       If the yaml config file does not end with a single blank line a
48
       cookiecutter.exceptions.InvalidConfiguration exception is thrown
49
       with an indecipherable error. This method fixes that by adding a
50
       trivial newline if it is missing.
51
       """
52
    if yaml_lines and yaml_lines[-1] != u'\n':
53
        yaml_lines.append(u'\n')
54
55
    return yaml_lines
56
57
58
def get_config(config_path):
59
    """
60
    Retrieve the config from the specified path, returning it as a config dict.
61
    """
62
63
    if not os.path.exists(config_path):
64
        raise ConfigDoesNotExistException
65
66
    logger.debug('config_path is {0}'.format(config_path))
67
    with io.open(config_path, encoding='utf-8') as file_handle:
68
        try:
69
            yaml_lines = file_handle.readlines()
70
            yaml_lines = _fix_missing_endline_in_yaml(yaml_lines)
71
            yaml_text = "".join(yaml_lines)
72
73
            yaml_dict = poyo.parse_string(yaml_text)
74
        except poyo.exceptions.PoyoException as e:
75
            raise InvalidConfiguration(
76
                'Unable to parse YAML file {}. Error: {}'
77
                ''.format(config_path, e)
78
            )
79
80
    config_dict = copy.copy(DEFAULT_CONFIG)
81
    config_dict.update(yaml_dict)
82
83
    raw_replay_dir = config_dict['replay_dir']
84
    config_dict['replay_dir'] = _expand_path(raw_replay_dir)
85
86
    raw_cookies_dir = config_dict['cookiecutters_dir']
87
    config_dict['cookiecutters_dir'] = _expand_path(raw_cookies_dir)
88
89
    return config_dict
90
91
92
def get_user_config(config_file=None, default_config=False):
93
    """Return the user config as a dict.
94
95
    If ``default_config`` is True, ignore ``config_file and return default
96
    values for the config parameters.
97
98
    If a path to a ``config_file`` is given, that is different from the default
99
    location, load the user config from that.
100
101
    Otherwise look up the config file path in the ``COOKIECUTTER_CONFIG``
102
    environment variable. If set, load the config from this path. This will
103
    raise an error if the specified path is not valid.
104
105
    If the environment variable is not set, try the default config file path
106
    before falling back to the default config values.
107
    """
108
    # Do NOT load a config. Return defaults instead.
109
    if default_config:
110
        return copy.copy(DEFAULT_CONFIG)
111
112
    # Load the given config file
113
    if config_file and config_file is not USER_CONFIG_PATH:
114
        return get_config(config_file)
115
116
    try:
117
        # Does the user set up a config environment variable?
118
        env_config_file = os.environ['COOKIECUTTER_CONFIG']
119
    except KeyError:
120
        # Load an optional user config if it exists
121
        # otherwise return the defaults
122
        if os.path.exists(USER_CONFIG_PATH):
123
            return get_config(USER_CONFIG_PATH)
124
        else:
125
            return copy.copy(DEFAULT_CONFIG)
126
    else:
127
        # There is a config environment variable. Try to load it.
128
        # Do not check for existence, so invalid file paths raise an error.
129
        return get_config(env_config_file)
130