Completed
Push — master ( 56245b...a9d00e )
by
unknown
38s
created

prompt_and_delete()   B

Complexity

Conditions 5

Size

Total Lines 37

Duplication

Lines 0
Ratio 0 %

Importance

Changes 2
Bugs 0 Features 1
Metric Value
cc 5
c 2
b 0
f 1
dl 0
loc 37
rs 8.0894
1
# -*- coding: utf-8 -*-
2
3
"""
4
cookiecutter.utils
5
------------------
6
7
Helper functions used throughout Cookiecutter.
8
"""
9
10
from __future__ import unicode_literals
11
import contextlib
12
import errno
13
import logging
14
import os
15
import stat
16
import shutil
17
import sys
18
19
from .prompt import read_user_yes_no
20
21
logger = logging.getLogger(__name__)
22
23
24
def force_delete(func, path, exc_info):
25
    """
26
    Error handler for `shutil.rmtree()` equivalent to `rm -rf`
27
    Usage: `shutil.rmtree(path, onerror=force_delete)`
28
    From stackoverflow.com/questions/1889597
29
    """
30
31
    os.chmod(path, stat.S_IWRITE)
32
    func(path)
33
34
35
def rmtree(path):
36
    """
37
    Removes a directory and all its contents. Like rm -rf on Unix.
38
39
    :param path: A directory path.
40
    """
41
42
    shutil.rmtree(path, onerror=force_delete)
43
44
45
def make_sure_path_exists(path):
46
    """
47
    Ensures that a directory exists.
48
49
    :param path: A directory path.
50
    """
51
52
    logger.debug('Making sure path exists: {}'.format(path))
53
    try:
54
        os.makedirs(path)
55
        logger.debug('Created directory at: {}'.format(path))
56
    except OSError as exception:
57
        if exception.errno != errno.EEXIST:
58
            return False
59
    return True
60
61
62
@contextlib.contextmanager
63
def work_in(dirname=None):
64
    """
65
    Context manager version of os.chdir. When exited, returns to the working
66
    directory prior to entering.
67
    """
68
    curdir = os.getcwd()
69
    try:
70
        if dirname is not None:
71
            os.chdir(dirname)
72
        yield
73
    finally:
74
        os.chdir(curdir)
75
76
77
def make_executable(script_path):
78
    """
79
    Makes `script_path` executable
80
81
    :param script_path: The file to change
82
    """
83
    status = os.stat(script_path)
84
    os.chmod(script_path, status.st_mode | stat.S_IEXEC)
85
86
87
def prompt_and_delete(path, no_input=False):
88
    """Ask the user whether it's okay to delete the previously-downloaded
89
    file/directory.
90
91
    If yes, delete it. If no, checks to see if the old version should be
92
    reused. If yes, it's reused; otherwise, Cookiecutter exits.
93
94
    :param path: Previously downloaded zipfile.
95
    :param no_input: Suppress prompt to delete repo and just delete it.
96
    :return: True if the content was deleted
97
    """
98
    # Suppress prompt if called via API
99
    if no_input:
100
        ok_to_delete = True
101
    else:
102
        question = (
103
            "You've downloaded {} before. "
104
            "Is it okay to delete and re-download it?"
105
        ).format(path)
106
107
        ok_to_delete = read_user_yes_no(question, 'yes')
108
109
    if ok_to_delete:
110
        if os.path.isdir(path):
111
            rmtree(path)
112
        else:
113
            os.remove(path)
114
        return True
115
    else:
116
        ok_to_reuse = read_user_yes_no(
117
            "Do you want to re-use the existing version?", 'yes'
118
        )
119
120
        if ok_to_reuse:
121
            return False
122
123
        sys.exit()
124