Completed
Push — master ( d86a98...27e7ec )
by Michael
01:21
created

validate_extra_context()   A

Complexity

Conditions 4

Size

Total Lines 11

Duplication

Lines 0
Ratio 0 %

Importance

Changes 2
Bugs 0 Features 0
Metric Value
cc 4
c 2
b 0
f 0
dl 0
loc 11
rs 9.2
1
#!/usr/bin/env python
2
# -*- coding: utf-8 -*-
3
4
"""
5
cookiecutter.cli
6
-----------------
7
8
Main `cookiecutter` CLI.
9
"""
10
11
import os
12
import sys
13
import logging
14
import json
15
16
import click
17
18
from cookiecutter import __version__
19
from cookiecutter.config import USER_CONFIG_PATH
20
from cookiecutter.main import cookiecutter
21
from cookiecutter.exceptions import (
22
    OutputDirExistsException,
23
    InvalidModeException,
24
    FailedHookException,
25
    UndefinedVariableInTemplate,
26
    UnknownExtension,
27
    RepositoryNotFound
28
)
29
30
logger = logging.getLogger(__name__)
31
32
33
def version_msg():
34
    """Returns the Cookiecutter version, location and Python powering it."""
35
    python_version = sys.version[:3]
36
    location = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
37
    message = u'Cookiecutter %(version)s from {} (Python {})'
38
    return message.format(location, python_version)
39
40
41
def validate_extra_context(ctx, param, value):
42
    for s in value:
43
        if '=' not in s:
44
            raise click.BadParameter(
45
                'EXTRA_CONTEXT should contain items of the form key=value; '
46
                "'{}' doesn't match that form".format(s)
47
            )
48
49
    # Convert tuple -- e.g.: (u'program_name=foobar', u'startsecs=66')
50
    # to dict -- e.g.: {'program_name': 'foobar', 'startsecs': '66'}
51
    return dict(s.split('=', 1) for s in value) or None
52
53
54
@click.command(context_settings=dict(help_option_names=[u'-h', u'--help']))
55
@click.version_option(__version__, u'-V', u'--version', message=version_msg())
56
@click.argument(u'template')
57
@click.argument(u'extra_context', nargs=-1, callback=validate_extra_context)
58
@click.option(
59
    u'--no-input', is_flag=True,
60
    help=u'Do not prompt for parameters and only use cookiecutter.json '
61
         u'file content',
62
)
63
@click.option(
64
    u'-c', u'--checkout',
65
    help=u'branch, tag or commit to checkout after git clone',
66
)
67
@click.option(
68
    '-v', '--verbose',
69
    is_flag=True, help='Print debug information', default=False
70
)
71
@click.option(
72
    u'--replay', is_flag=True,
73
    help=u'Do not prompt for parameters and only use information entered '
74
         u'previously',
75
)
76
@click.option(
77
    u'-f', u'--overwrite-if-exists', is_flag=True,
78
    help=u'Overwrite the contents of the output directory if it already exists'
79
)
80
@click.option(
81
    u'-o', u'--output-dir', default='.', type=click.Path(),
82
    help=u'Where to output the generated project dir into'
83
)
84
@click.option(
85
    u'--config-file', type=click.Path(), default=USER_CONFIG_PATH,
86
    help=u'User configuration file'
87
)
88
@click.option(
89
    u'--default-config', is_flag=True,
90
    help=u'Do not load a config file. Use the defaults instead'
91
)
92
def main(template, extra_context, no_input, checkout, verbose, replay,
93
         overwrite_if_exists, output_dir, config_file, default_config):
94
    """Create a project from a Cookiecutter project template (TEMPLATE)."""
95
    if verbose:
96
        logging.basicConfig(
97
            format=u'%(levelname)s %(filename)s: %(message)s',
98
            level=logging.DEBUG
99
        )
100
    else:
101
        # Log info and above to console
102
        logging.basicConfig(
103
            format=u'%(levelname)s: %(message)s',
104
            level=logging.INFO
105
        )
106
107
    try:
108
        # If you _need_ to support a local template in a directory
109
        # called 'help', use a qualified path to the directory.
110
        if template == u'help':
111
            click.echo(click.get_current_context().get_help())
112
            sys.exit(0)
113
114
        user_config = None if default_config else config_file
115
116
        cookiecutter(
117
            template, checkout, no_input,
118
            extra_context=extra_context,
119
            replay=replay,
120
            overwrite_if_exists=overwrite_if_exists,
121
            output_dir=output_dir,
122
            config_file=user_config
123
        )
124
    except (OutputDirExistsException,
125
            InvalidModeException,
126
            FailedHookException,
127
            UnknownExtension,
128
            RepositoryNotFound) as e:
129
        click.echo(e)
130
        sys.exit(1)
131
    except UndefinedVariableInTemplate as undefined_err:
132
        click.echo('{}'.format(undefined_err.message))
133
        click.echo('Error message: {}'.format(undefined_err.error.message))
134
135
        context_str = json.dumps(
136
            undefined_err.context,
137
            indent=4,
138
            sort_keys=True
139
        )
140
        click.echo('Context: {}'.format(context_str))
141
        sys.exit(1)
142
143
144
if __name__ == "__main__":
145
    main()
146