1
|
|
|
from __future__ import absolute_import |
2
|
|
|
|
3
|
|
|
import os |
4
|
|
|
import requests |
5
|
|
|
import sys |
6
|
|
|
from zipfile import ZipFile |
7
|
|
|
|
8
|
|
|
from .prompt import read_user_yes_no |
9
|
|
|
from .utils import make_sure_path_exists, rmtree |
10
|
|
|
|
11
|
|
|
|
12
|
|
|
def prompt_and_delete(path, no_input=False): |
13
|
|
|
"""Ask the user whether it's okay to delete the previously-downloaded |
14
|
|
|
file/directory. |
15
|
|
|
|
16
|
|
|
If yes, deletes it. Otherwise, Cookiecutter exits. |
17
|
|
|
|
18
|
|
|
:param path: Previously downloaded zipfile. |
19
|
|
|
:param no_input: Suppress prompt to delete repo and just delete it. |
20
|
|
|
""" |
21
|
|
|
# Suppress prompt if called via API |
22
|
|
|
if no_input: |
23
|
|
|
ok_to_delete = True |
24
|
|
|
else: |
25
|
|
|
question = ( |
26
|
|
|
"You've downloaded {} before. " |
27
|
|
|
"Is it okay to delete and re-download it?" |
28
|
|
|
).format(path) |
29
|
|
|
|
30
|
|
|
ok_to_delete = read_user_yes_no(question, 'yes') |
31
|
|
|
|
32
|
|
|
if ok_to_delete: |
33
|
|
|
if os.path.isdir(path): |
34
|
|
|
rmtree(path) |
35
|
|
|
else: |
36
|
|
|
os.remove(path) |
37
|
|
|
else: |
38
|
|
|
sys.exit() |
39
|
|
|
|
40
|
|
|
return ok_to_delete |
41
|
|
|
|
42
|
|
|
|
43
|
|
|
def unzip(zip_url, is_url, clone_to_dir='.', no_input=False): |
44
|
|
|
# Ensure that clone_to_dir exists |
45
|
|
|
clone_to_dir = os.path.expanduser(clone_to_dir) |
46
|
|
|
make_sure_path_exists(clone_to_dir) |
47
|
|
|
|
48
|
|
|
if is_url: |
49
|
|
|
# Build the name of the cached zipfile, |
50
|
|
|
# and prompt to delete if it already exists. |
51
|
|
|
identifier = zip_url.rsplit('/', 1)[1] |
52
|
|
|
zip_path = os.path.join(clone_to_dir, identifier) |
53
|
|
|
|
54
|
|
|
if os.path.exists(zip_path): |
55
|
|
|
ok_to_delete = prompt_and_delete(zip_path, no_input=no_input) |
56
|
|
|
else: |
57
|
|
|
ok_to_delete = None |
58
|
|
|
|
59
|
|
|
# (Re) download the zipfile |
60
|
|
|
r = requests.get(zip_url, stream=True) |
61
|
|
|
with open(zip_path, 'wb') as f: |
62
|
|
|
for chunk in r.iter_content(chunk_size=1024): |
63
|
|
|
if chunk: # filter out keep-alive new chunks |
64
|
|
|
f.write(chunk) |
65
|
|
|
else: |
66
|
|
|
# Just use the local zipfile as-is. |
67
|
|
|
zip_path = os.path.abspath(zip_url) |
68
|
|
|
ok_to_delete = None |
69
|
|
|
|
70
|
|
|
# Now unpack the repository. The zipfile will include |
71
|
|
|
# the name of the template as the top level directory; |
72
|
|
|
# Check if that directory already exists, and if so, |
73
|
|
|
# prompt for deletion. If we've previously OK'd deletion, |
74
|
|
|
# don't ask again. |
75
|
|
|
zip_file = ZipFile(zip_path) |
76
|
|
|
unzip_name = zip_file.namelist()[0][:-1] |
77
|
|
|
|
78
|
|
|
unzip_path = os.path.join(clone_to_dir, unzip_name) |
79
|
|
|
if os.path.exists(unzip_path): |
80
|
|
|
if ok_to_delete is None: |
81
|
|
|
ok_to_delete = prompt_and_delete(unzip_path, no_input=no_input) |
82
|
|
|
else: |
83
|
|
|
rmtree(unzip_path) |
84
|
|
|
|
85
|
|
|
# Extract the zip file |
86
|
|
|
zip_file.extractall(path=clone_to_dir) |
87
|
|
|
|
88
|
|
|
return unzip_path |
89
|
|
|
|