forked from cookiecutter/cookiecutter
-
Notifications
You must be signed in to change notification settings - Fork 0
/
repository.py
131 lines (108 loc) · 4.14 KB
/
repository.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
"""Cookiecutter repository functions."""
import os
import re
from cookiecutter.exceptions import RepositoryNotFound
from cookiecutter.vcs import clone
from cookiecutter.zipfile import unzip
REPO_REGEX = re.compile(
r"""
# something like git:// ssh:// file:// etc.
((((git|hg)\+)?(git|ssh|file|https?):(//)?)
| # or
(\w+@[\w\.]+) # something like user@...
)
""",
re.VERBOSE,
)
def is_repo_url(value):
"""Return True if value is a repository URL."""
return bool(REPO_REGEX.match(value))
def is_zip_file(value):
"""Return True if value is a zip file."""
return value.lower().endswith('.zip')
def expand_abbreviations(template, abbreviations):
"""Expand abbreviations in a template name.
:param template: The project template name.
:param abbreviations: Abbreviation definitions.
"""
if template in abbreviations:
return abbreviations[template]
# Split on colon. If there is no colon, rest will be empty
# and prefix will be the whole template
prefix, sep, rest = template.partition(':')
if prefix in abbreviations:
return abbreviations[prefix].format(rest)
return template
def repository_has_cookiecutter_json(repo_directory):
"""Determine if `repo_directory` contains a `cookiecutter.json` file.
:param repo_directory: The candidate repository directory.
:return: True if the `repo_directory` is valid, else False.
"""
repo_directory_exists = os.path.isdir(repo_directory)
repo_config_exists = os.path.isfile(
os.path.join(repo_directory, 'cookiecutter.json')
)
return repo_directory_exists and repo_config_exists
def determine_repo_dir(
template,
abbreviations,
clone_to_dir,
checkout,
no_input,
password=None,
directory=None,
):
"""
Locate the repository directory from a template reference.
Applies repository abbreviations to the template reference.
If the template refers to a repository URL, clone it.
If the template is a path to a local repository, use it.
:param template: A directory containing a project template directory,
or a URL to a git repository.
:param abbreviations: A dictionary of repository abbreviation
definitions.
:param clone_to_dir: The directory to clone the repository into.
:param checkout: The branch, tag or commit ID to checkout after clone.
:param no_input: Do not prompt for user input and eventually force a refresh of
cached resources.
:param password: The password to use when extracting the repository.
:param directory: Directory within repo where cookiecutter.json lives.
:return: A tuple containing the cookiecutter template directory, and
a boolean describing whether that directory should be cleaned up
after the template has been instantiated.
:raises: `RepositoryNotFound` if a repository directory could not be found.
"""
template = expand_abbreviations(template, abbreviations)
if is_zip_file(template):
unzipped_dir = unzip(
zip_uri=template,
is_url=is_repo_url(template),
clone_to_dir=clone_to_dir,
no_input=no_input,
password=password,
)
repository_candidates = [unzipped_dir]
cleanup = True
elif is_repo_url(template):
cloned_repo = clone(
repo_url=template,
checkout=checkout,
clone_to_dir=clone_to_dir,
no_input=no_input,
)
repository_candidates = [cloned_repo]
cleanup = False
else:
repository_candidates = [template, os.path.join(clone_to_dir, template)]
cleanup = False
if directory:
repository_candidates = [
os.path.join(s, directory) for s in repository_candidates
]
for repo_candidate in repository_candidates:
if repository_has_cookiecutter_json(repo_candidate):
return repo_candidate, cleanup
raise RepositoryNotFound(
'A valid repository for "{}" could not be found in the following '
'locations:\n{}'.format(template, '\n'.join(repository_candidates))
)