Passed
Push — master ( 0b4062...c0e769 )
by
unknown
05:31
created

_patch_import_path_for_repo.__init__()   A

Complexity

Conditions 1

Size

Total Lines 3
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
eloc 3
dl 0
loc 3
rs 10
c 0
b 0
f 0
cc 1
nop 2
1
"""
2
Main entry point for the `cookiecutter` command.
3
4
The code in this module is also a good example of how to use Cookiecutter as a
5
library rather than a script.
6
"""
7
from copy import copy
8
import logging
9
import os
10
import sys
11
12
from cookiecutter.config import get_user_config
13
from cookiecutter.exceptions import InvalidModeException
14
from cookiecutter.generate import generate_context, generate_files
15
from cookiecutter.prompt import prompt_for_config
16
from cookiecutter.replay import dump, load
17
from cookiecutter.repository import determine_repo_dir
18
from cookiecutter.utils import rmtree
19
20
logger = logging.getLogger(__name__)
21
22
23
def cookiecutter(
24
    template,
25
    checkout=None,
26
    no_input=False,
27
    extra_context=None,
28
    replay=None,
29
    overwrite_if_exists=False,
30
    output_dir='.',
31
    config_file=None,
32
    default_config=False,
33
    password=None,
34
    directory=None,
35
    skip_if_file_exists=False,
36
    accept_hooks=True,
37
):
38
    """
39
    Run Cookiecutter just as if using it from the command line.
40
41
    :param template: A directory containing a project template directory,
42
        or a URL to a git repository.
43
    :param checkout: The branch, tag or commit ID to checkout after clone.
44
    :param no_input: Prompt the user at command line for manual configuration?
45
    :param extra_context: A dictionary of context that overrides default
46
        and user configuration.
47
    :param replay: Do not prompt for input, instead read from saved json. If
48
        ``True`` read from the ``replay_dir``.
49
        if it exists
50
    :param output_dir: Where to output the generated project dir into.
51
    :param config_file: User configuration file path.
52
    :param default_config: Use default values rather than a config file.
53
    :param password: The password to use when extracting the repository.
54
    :param directory: Relative path to a cookiecutter template in a repository.
55
    :param accept_hooks: Accept pre and post hooks if set to `True`.
56
    """
57
    if replay and ((no_input is not False) or (extra_context is not None)):
58
        err_msg = (
59
            "You can not use both replay and no_input or extra_context "
60
            "at the same time."
61
        )
62
        raise InvalidModeException(err_msg)
63
64
    config_dict = get_user_config(
65
        config_file=config_file,
66
        default_config=default_config,
67
    )
68
69
    repo_dir, cleanup = determine_repo_dir(
70
        template=template,
71
        abbreviations=config_dict['abbreviations'],
72
        clone_to_dir=config_dict['cookiecutters_dir'],
73
        checkout=checkout,
74
        no_input=no_input,
75
        password=password,
76
        directory=directory,
77
    )
78
    import_patch = _patch_import_path_for_repo(repo_dir)
79
80
    template_name = os.path.basename(os.path.abspath(repo_dir))
81
82
    if replay:
83
        with import_patch:
84
            if isinstance(replay, bool):
85
                context = load(config_dict['replay_dir'], template_name)
86
            else:
87
                path, template_name = os.path.split(os.path.splitext(replay)[0])
88
                context = load(path, template_name)
89
    else:
90
        context_file = os.path.join(repo_dir, 'cookiecutter.json')
91
        logger.debug('context_file is %s', context_file)
92
93
        context = generate_context(
94
            context_file=context_file,
95
            default_context=config_dict['default_context'],
96
            extra_context=extra_context,
97
        )
98
99
        # prompt the user to manually configure at the command line.
100
        # except when 'no-input' flag is set
101
        with import_patch:
102
            context['cookiecutter'] = prompt_for_config(context, no_input)
103
104
        # include template dir or url in the context dict
105
        context['cookiecutter']['_template'] = template
106
107
        # include output+dir in the context dict
108
        context['cookiecutter']['_output_dir'] = os.path.abspath(output_dir)
109
110
        dump(config_dict['replay_dir'], template_name, context)
111
112
    # Create project from local context and project template.
113
    with import_patch:
114
        result = generate_files(
115
            repo_dir=repo_dir,
116
            context=context,
117
            overwrite_if_exists=overwrite_if_exists,
118
            skip_if_file_exists=skip_if_file_exists,
119
            output_dir=output_dir,
120
            accept_hooks=accept_hooks,
121
        )
122
123
    # Cleanup (if required)
124
    if cleanup:
125
        rmtree(repo_dir)
126
127
    return result
128
129
130
class _patch_import_path_for_repo:
131
    def __init__(self, repo_dir):
132
        self._repo_dir = repo_dir
133
        self._path = None
134
135
    def __enter__(self):
136
        self._path = copy(sys.path)
137
        sys.path.append(self._repo_dir)
138
139
    def __exit__(self, type, value, traceback):
140
        sys.path = self._path
141