diff options
| author | Shubham Saini <shubham6405@gmail.com> | 2018-12-11 10:01:23 +0000 |
|---|---|---|
| committer | Shubham Saini <shubham6405@gmail.com> | 2018-12-11 10:01:23 +0000 |
| commit | 68df54d6629ec019142eb149dd037774f2d11e7c (patch) | |
| tree | 345bc22d46b4e01a4ba8303b94278952a4ed2b9e /venv/lib/python3.7/site-packages/pip-10.0.1-py3.7.egg/pip/_internal/vcs/git.py | |
First commit
Diffstat (limited to 'venv/lib/python3.7/site-packages/pip-10.0.1-py3.7.egg/pip/_internal/vcs/git.py')
| -rw-r--r-- | venv/lib/python3.7/site-packages/pip-10.0.1-py3.7.egg/pip/_internal/vcs/git.py | 311 |
1 files changed, 311 insertions, 0 deletions
diff --git a/venv/lib/python3.7/site-packages/pip-10.0.1-py3.7.egg/pip/_internal/vcs/git.py b/venv/lib/python3.7/site-packages/pip-10.0.1-py3.7.egg/pip/_internal/vcs/git.py new file mode 100644 index 0000000..7a63dfa --- /dev/null +++ b/venv/lib/python3.7/site-packages/pip-10.0.1-py3.7.egg/pip/_internal/vcs/git.py | |||
| @@ -0,0 +1,311 @@ | |||
| 1 | from __future__ import absolute_import | ||
| 2 | |||
| 3 | import logging | ||
| 4 | import os.path | ||
| 5 | import re | ||
| 6 | |||
| 7 | from pip._vendor.packaging.version import parse as parse_version | ||
| 8 | from pip._vendor.six.moves.urllib import parse as urllib_parse | ||
| 9 | from pip._vendor.six.moves.urllib import request as urllib_request | ||
| 10 | |||
| 11 | from pip._internal.compat import samefile | ||
| 12 | from pip._internal.exceptions import BadCommand | ||
| 13 | from pip._internal.utils.misc import display_path | ||
| 14 | from pip._internal.utils.temp_dir import TempDirectory | ||
| 15 | from pip._internal.vcs import VersionControl, vcs | ||
| 16 | |||
| 17 | urlsplit = urllib_parse.urlsplit | ||
| 18 | urlunsplit = urllib_parse.urlunsplit | ||
| 19 | |||
| 20 | |||
| 21 | logger = logging.getLogger(__name__) | ||
| 22 | |||
| 23 | |||
| 24 | HASH_REGEX = re.compile('[a-fA-F0-9]{40}') | ||
| 25 | |||
| 26 | |||
| 27 | def looks_like_hash(sha): | ||
| 28 | return bool(HASH_REGEX.match(sha)) | ||
| 29 | |||
| 30 | |||
| 31 | class Git(VersionControl): | ||
| 32 | name = 'git' | ||
| 33 | dirname = '.git' | ||
| 34 | repo_name = 'clone' | ||
| 35 | schemes = ( | ||
| 36 | 'git', 'git+http', 'git+https', 'git+ssh', 'git+git', 'git+file', | ||
| 37 | ) | ||
| 38 | # Prevent the user's environment variables from interfering with pip: | ||
| 39 | # https://github.com/pypa/pip/issues/1130 | ||
| 40 | unset_environ = ('GIT_DIR', 'GIT_WORK_TREE') | ||
| 41 | default_arg_rev = 'HEAD' | ||
| 42 | |||
| 43 | def __init__(self, url=None, *args, **kwargs): | ||
| 44 | |||
| 45 | # Works around an apparent Git bug | ||
| 46 | # (see http://article.gmane.org/gmane.comp.version-control.git/146500) | ||
| 47 | if url: | ||
| 48 | scheme, netloc, path, query, fragment = urlsplit(url) | ||
| 49 | if scheme.endswith('file'): | ||
| 50 | initial_slashes = path[:-len(path.lstrip('/'))] | ||
| 51 | newpath = ( | ||
| 52 | initial_slashes + | ||
| 53 | urllib_request.url2pathname(path) | ||
| 54 | .replace('\\', '/').lstrip('/') | ||
| 55 | ) | ||
| 56 | url = urlunsplit((scheme, netloc, newpath, query, fragment)) | ||
| 57 | after_plus = scheme.find('+') + 1 | ||
| 58 | url = scheme[:after_plus] + urlunsplit( | ||
| 59 | (scheme[after_plus:], netloc, newpath, query, fragment), | ||
| 60 | ) | ||
| 61 | |||
| 62 | super(Git, self).__init__(url, *args, **kwargs) | ||
| 63 | |||
| 64 | def get_base_rev_args(self, rev): | ||
| 65 | return [rev] | ||
| 66 | |||
| 67 | def get_git_version(self): | ||
| 68 | VERSION_PFX = 'git version ' | ||
| 69 | version = self.run_command(['version'], show_stdout=False) | ||
| 70 | if version.startswith(VERSION_PFX): | ||
| 71 | version = version[len(VERSION_PFX):].split()[0] | ||
| 72 | else: | ||
| 73 | version = '' | ||
| 74 | # get first 3 positions of the git version becasue | ||
| 75 | # on windows it is x.y.z.windows.t, and this parses as | ||
| 76 | # LegacyVersion which always smaller than a Version. | ||
| 77 | version = '.'.join(version.split('.')[:3]) | ||
| 78 | return parse_version(version) | ||
| 79 | |||
| 80 | def export(self, location): | ||
| 81 | """Export the Git repository at the url to the destination location""" | ||
| 82 | if not location.endswith('/'): | ||
| 83 | location = location + '/' | ||
| 84 | |||
| 85 | with TempDirectory(kind="export") as temp_dir: | ||
| 86 | self.unpack(temp_dir.path) | ||
| 87 | self.run_command( | ||
| 88 | ['checkout-index', '-a', '-f', '--prefix', location], | ||
| 89 | show_stdout=False, cwd=temp_dir.path | ||
| 90 | ) | ||
| 91 | |||
| 92 | def get_revision_sha(self, dest, rev): | ||
| 93 | """ | ||
| 94 | Return a commit hash for the given revision if it names a remote | ||
| 95 | branch or tag. Otherwise, return None. | ||
| 96 | |||
| 97 | Args: | ||
| 98 | dest: the repository directory. | ||
| 99 | rev: the revision name. | ||
| 100 | """ | ||
| 101 | # Pass rev to pre-filter the list. | ||
| 102 | output = self.run_command(['show-ref', rev], cwd=dest, | ||
| 103 | show_stdout=False, on_returncode='ignore') | ||
| 104 | refs = {} | ||
| 105 | for line in output.strip().splitlines(): | ||
| 106 | try: | ||
| 107 | sha, ref = line.split() | ||
| 108 | except ValueError: | ||
| 109 | # Include the offending line to simplify troubleshooting if | ||
| 110 | # this error ever occurs. | ||
| 111 | raise ValueError('unexpected show-ref line: {!r}'.format(line)) | ||
| 112 | |||
| 113 | refs[ref] = sha | ||
| 114 | |||
| 115 | branch_ref = 'refs/remotes/origin/{}'.format(rev) | ||
| 116 | tag_ref = 'refs/tags/{}'.format(rev) | ||
| 117 | |||
| 118 | return refs.get(branch_ref) or refs.get(tag_ref) | ||
| 119 | |||
| 120 | def check_rev_options(self, dest, rev_options): | ||
| 121 | """Check the revision options before checkout. | ||
| 122 | |||
| 123 | Returns a new RevOptions object for the SHA1 of the branch or tag | ||
| 124 | if found. | ||
| 125 | |||
| 126 | Args: | ||
| 127 | rev_options: a RevOptions object. | ||
| 128 | """ | ||
| 129 | rev = rev_options.arg_rev | ||
| 130 | sha = self.get_revision_sha(dest, rev) | ||
| 131 | |||
| 132 | if sha is not None: | ||
| 133 | return rev_options.make_new(sha) | ||
| 134 | |||
| 135 | # Do not show a warning for the common case of something that has | ||
| 136 | # the form of a Git commit hash. | ||
| 137 | if not looks_like_hash(rev): | ||
| 138 | logger.warning( | ||
| 139 | "Did not find branch or tag '%s', assuming revision or ref.", | ||
| 140 | rev, | ||
| 141 | ) | ||
| 142 | return rev_options | ||
| 143 | |||
| 144 | def is_commit_id_equal(self, dest, name): | ||
| 145 | """ | ||
| 146 | Return whether the current commit hash equals the given name. | ||
| 147 | |||
| 148 | Args: | ||
| 149 | dest: the repository directory. | ||
| 150 | name: a string name. | ||
| 151 | """ | ||
| 152 | if not name: | ||
| 153 | # Then avoid an unnecessary subprocess call. | ||
| 154 | return False | ||
| 155 | |||
| 156 | return self.get_revision(dest) == name | ||
| 157 | |||
| 158 | def switch(self, dest, url, rev_options): | ||
| 159 | self.run_command(['config', 'remote.origin.url', url], cwd=dest) | ||
| 160 | cmd_args = ['checkout', '-q'] + rev_options.to_args() | ||
| 161 | self.run_command(cmd_args, cwd=dest) | ||
| 162 | |||
| 163 | self.update_submodules(dest) | ||
| 164 | |||
| 165 | def update(self, dest, rev_options): | ||
| 166 | # First fetch changes from the default remote | ||
| 167 | if self.get_git_version() >= parse_version('1.9.0'): | ||
| 168 | # fetch tags in addition to everything else | ||
| 169 | self.run_command(['fetch', '-q', '--tags'], cwd=dest) | ||
| 170 | else: | ||
| 171 | self.run_command(['fetch', '-q'], cwd=dest) | ||
| 172 | # Then reset to wanted revision (maybe even origin/master) | ||
| 173 | rev_options = self.check_rev_options(dest, rev_options) | ||
| 174 | cmd_args = ['reset', '--hard', '-q'] + rev_options.to_args() | ||
| 175 | self.run_command(cmd_args, cwd=dest) | ||
| 176 | #: update submodules | ||
| 177 | self.update_submodules(dest) | ||
| 178 | |||
| 179 | def obtain(self, dest): | ||
| 180 | url, rev = self.get_url_rev() | ||
| 181 | rev_options = self.make_rev_options(rev) | ||
| 182 | if self.check_destination(dest, url, rev_options): | ||
| 183 | rev_display = rev_options.to_display() | ||
| 184 | logger.info( | ||
| 185 | 'Cloning %s%s to %s', url, rev_display, display_path(dest), | ||
| 186 | ) | ||
| 187 | self.run_command(['clone', '-q', url, dest]) | ||
| 188 | |||
| 189 | if rev: | ||
| 190 | rev_options = self.check_rev_options(dest, rev_options) | ||
| 191 | # Only do a checkout if the current commit id doesn't match | ||
| 192 | # the requested revision. | ||
| 193 | if not self.is_commit_id_equal(dest, rev_options.rev): | ||
| 194 | rev = rev_options.rev | ||
| 195 | # Only fetch the revision if it's a ref | ||
| 196 | if rev.startswith('refs/'): | ||
| 197 | self.run_command( | ||
| 198 | ['fetch', '-q', url] + rev_options.to_args(), | ||
| 199 | cwd=dest, | ||
| 200 | ) | ||
| 201 | # Change the revision to the SHA of the ref we fetched | ||
| 202 | rev = 'FETCH_HEAD' | ||
| 203 | self.run_command(['checkout', '-q', rev], cwd=dest) | ||
| 204 | |||
| 205 | #: repo may contain submodules | ||
| 206 | self.update_submodules(dest) | ||
| 207 | |||
| 208 | def get_url(self, location): | ||
| 209 | """Return URL of the first remote encountered.""" | ||
| 210 | remotes = self.run_command( | ||
| 211 | ['config', '--get-regexp', r'remote\..*\.url'], | ||
| 212 | show_stdout=False, cwd=location, | ||
| 213 | ) | ||
| 214 | remotes = remotes.splitlines() | ||
| 215 | found_remote = remotes[0] | ||
| 216 | for remote in remotes: | ||
| 217 | if remote.startswith('remote.origin.url '): | ||
| 218 | found_remote = remote | ||
| 219 | break | ||
| 220 | url = found_remote.split(' ')[1] | ||
| 221 | return url.strip() | ||
| 222 | |||
| 223 | def get_revision(self, location): | ||
| 224 | current_rev = self.run_command( | ||
| 225 | ['rev-parse', 'HEAD'], show_stdout=False, cwd=location, | ||
| 226 | ) | ||
| 227 | return current_rev.strip() | ||
| 228 | |||
| 229 | def _get_subdirectory(self, location): | ||
| 230 | """Return the relative path of setup.py to the git repo root.""" | ||
| 231 | # find the repo root | ||
| 232 | git_dir = self.run_command(['rev-parse', '--git-dir'], | ||
| 233 | show_stdout=False, cwd=location).strip() | ||
| 234 | if not os.path.isabs(git_dir): | ||
| 235 | git_dir = os.path.join(location, git_dir) | ||
| 236 | root_dir = os.path.join(git_dir, '..') | ||
| 237 | # find setup.py | ||
| 238 | orig_location = location | ||
| 239 | while not os.path.exists(os.path.join(location, 'setup.py')): | ||
| 240 | last_location = location | ||
| 241 | location = os.path.dirname(location) | ||
| 242 | if location == last_location: | ||
| 243 | # We've traversed up to the root of the filesystem without | ||
| 244 | # finding setup.py | ||
| 245 | logger.warning( | ||
| 246 | "Could not find setup.py for directory %s (tried all " | ||
| 247 | "parent directories)", | ||
| 248 | orig_location, | ||
| 249 | ) | ||
| 250 | return None | ||
| 251 | # relative path of setup.py to repo root | ||
| 252 | if samefile(root_dir, location): | ||
| 253 | return None | ||
| 254 | return os.path.relpath(location, root_dir) | ||
| 255 | |||
| 256 | def get_src_requirement(self, dist, location): | ||
| 257 | repo = self.get_url(location) | ||
| 258 | if not repo.lower().startswith('git:'): | ||
| 259 | repo = 'git+' + repo | ||
| 260 | egg_project_name = dist.egg_name().split('-', 1)[0] | ||
| 261 | if not repo: | ||
| 262 | return None | ||
| 263 | current_rev = self.get_revision(location) | ||
| 264 | req = '%s@%s#egg=%s' % (repo, current_rev, egg_project_name) | ||
| 265 | subdirectory = self._get_subdirectory(location) | ||
| 266 | if subdirectory: | ||
| 267 | req += '&subdirectory=' + subdirectory | ||
| 268 | return req | ||
| 269 | |||
| 270 | def get_url_rev(self): | ||
| 271 | """ | ||
| 272 | Prefixes stub URLs like 'user@hostname:user/repo.git' with 'ssh://'. | ||
| 273 | That's required because although they use SSH they sometimes doesn't | ||
| 274 | work with a ssh:// scheme (e.g. Github). But we need a scheme for | ||
| 275 | parsing. Hence we remove it again afterwards and return it as a stub. | ||
| 276 | """ | ||
| 277 | if '://' not in self.url: | ||
| 278 | assert 'file:' not in self.url | ||
| 279 | self.url = self.url.replace('git+', 'git+ssh://') | ||
| 280 | url, rev = super(Git, self).get_url_rev() | ||
| 281 | url = url.replace('ssh://', '') | ||
| 282 | else: | ||
| 283 | url, rev = super(Git, self).get_url_rev() | ||
| 284 | |||
| 285 | return url, rev | ||
| 286 | |||
| 287 | def update_submodules(self, location): | ||
| 288 | if not os.path.exists(os.path.join(location, '.gitmodules')): | ||
| 289 | return | ||
| 290 | self.run_command( | ||
| 291 | ['submodule', 'update', '--init', '--recursive', '-q'], | ||
| 292 | cwd=location, | ||
| 293 | ) | ||
| 294 | |||
| 295 | @classmethod | ||
| 296 | def controls_location(cls, location): | ||
| 297 | if super(Git, cls).controls_location(location): | ||
| 298 | return True | ||
| 299 | try: | ||
| 300 | r = cls().run_command(['rev-parse'], | ||
| 301 | cwd=location, | ||
| 302 | show_stdout=False, | ||
| 303 | on_returncode='ignore') | ||
| 304 | return not r | ||
| 305 | except BadCommand: | ||
| 306 | logger.debug("could not determine if %s is under git control " | ||
| 307 | "because git is not available", location) | ||
| 308 | return False | ||
| 309 | |||
| 310 | |||
| 311 | vcs.register(Git) | ||
