Completed
Push — master ( e8315c...073098 )
by Michael
26s
created

prompt_and_delete()   B

Complexity

Conditions 5

Size

Total Lines 37

Duplication

Lines 0
Ratio 0 %

Importance

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