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 |
First commit
Diffstat (limited to 'venv/lib/python3.7/site-packages/pip-10.0.1-py3.7.egg/pip/_internal/vcs')
5 files changed, 1271 insertions, 0 deletions
diff --git a/venv/lib/python3.7/site-packages/pip-10.0.1-py3.7.egg/pip/_internal/vcs/__init__.py b/venv/lib/python3.7/site-packages/pip-10.0.1-py3.7.egg/pip/_internal/vcs/__init__.py new file mode 100644 index 0000000..bff94fa --- /dev/null +++ b/venv/lib/python3.7/site-packages/pip-10.0.1-py3.7.egg/pip/_internal/vcs/__init__.py | |||
@@ -0,0 +1,471 @@ | |||
1 | """Handles all VCS (version control) support""" | ||
2 | from __future__ import absolute_import | ||
3 | |||
4 | import copy | ||
5 | import errno | ||
6 | import logging | ||
7 | import os | ||
8 | import shutil | ||
9 | import sys | ||
10 | |||
11 | from pip._vendor.six.moves.urllib import parse as urllib_parse | ||
12 | |||
13 | from pip._internal.exceptions import BadCommand | ||
14 | from pip._internal.utils.misc import ( | ||
15 | display_path, backup_dir, call_subprocess, rmtree, ask_path_exists, | ||
16 | ) | ||
17 | from pip._internal.utils.typing import MYPY_CHECK_RUNNING | ||
18 | |||
19 | if MYPY_CHECK_RUNNING: | ||
20 | from typing import Dict, Optional, Tuple | ||
21 | from pip._internal.basecommand import Command | ||
22 | |||
23 | __all__ = ['vcs', 'get_src_requirement'] | ||
24 | |||
25 | |||
26 | logger = logging.getLogger(__name__) | ||
27 | |||
28 | |||
29 | class RevOptions(object): | ||
30 | |||
31 | """ | ||
32 | Encapsulates a VCS-specific revision to install, along with any VCS | ||
33 | install options. | ||
34 | |||
35 | Instances of this class should be treated as if immutable. | ||
36 | """ | ||
37 | |||
38 | def __init__(self, vcs, rev=None, extra_args=None): | ||
39 | """ | ||
40 | Args: | ||
41 | vcs: a VersionControl object. | ||
42 | rev: the name of the revision to install. | ||
43 | extra_args: a list of extra options. | ||
44 | """ | ||
45 | if extra_args is None: | ||
46 | extra_args = [] | ||
47 | |||
48 | self.extra_args = extra_args | ||
49 | self.rev = rev | ||
50 | self.vcs = vcs | ||
51 | |||
52 | def __repr__(self): | ||
53 | return '<RevOptions {}: rev={!r}>'.format(self.vcs.name, self.rev) | ||
54 | |||
55 | @property | ||
56 | def arg_rev(self): | ||
57 | if self.rev is None: | ||
58 | return self.vcs.default_arg_rev | ||
59 | |||
60 | return self.rev | ||
61 | |||
62 | def to_args(self): | ||
63 | """ | ||
64 | Return the VCS-specific command arguments. | ||
65 | """ | ||
66 | args = [] | ||
67 | rev = self.arg_rev | ||
68 | if rev is not None: | ||
69 | args += self.vcs.get_base_rev_args(rev) | ||
70 | args += self.extra_args | ||
71 | |||
72 | return args | ||
73 | |||
74 | def to_display(self): | ||
75 | if not self.rev: | ||
76 | return '' | ||
77 | |||
78 | return ' (to revision {})'.format(self.rev) | ||
79 | |||
80 | def make_new(self, rev): | ||
81 | """ | ||
82 | Make a copy of the current instance, but with a new rev. | ||
83 | |||
84 | Args: | ||
85 | rev: the name of the revision for the new object. | ||
86 | """ | ||
87 | return self.vcs.make_rev_options(rev, extra_args=self.extra_args) | ||
88 | |||
89 | |||
90 | class VcsSupport(object): | ||
91 | _registry = {} # type: Dict[str, Command] | ||
92 | schemes = ['ssh', 'git', 'hg', 'bzr', 'sftp', 'svn'] | ||
93 | |||
94 | def __init__(self): | ||
95 | # Register more schemes with urlparse for various version control | ||
96 | # systems | ||
97 | urllib_parse.uses_netloc.extend(self.schemes) | ||
98 | # Python >= 2.7.4, 3.3 doesn't have uses_fragment | ||
99 | if getattr(urllib_parse, 'uses_fragment', None): | ||
100 | urllib_parse.uses_fragment.extend(self.schemes) | ||
101 | super(VcsSupport, self).__init__() | ||
102 | |||
103 | def __iter__(self): | ||
104 | return self._registry.__iter__() | ||
105 | |||
106 | @property | ||
107 | def backends(self): | ||
108 | return list(self._registry.values()) | ||
109 | |||
110 | @property | ||
111 | def dirnames(self): | ||
112 | return [backend.dirname for backend in self.backends] | ||
113 | |||
114 | @property | ||
115 | def all_schemes(self): | ||
116 | schemes = [] | ||
117 | for backend in self.backends: | ||
118 | schemes.extend(backend.schemes) | ||
119 | return schemes | ||
120 | |||
121 | def register(self, cls): | ||
122 | if not hasattr(cls, 'name'): | ||
123 | logger.warning('Cannot register VCS %s', cls.__name__) | ||
124 | return | ||
125 | if cls.name not in self._registry: | ||
126 | self._registry[cls.name] = cls | ||
127 | logger.debug('Registered VCS backend: %s', cls.name) | ||
128 | |||
129 | def unregister(self, cls=None, name=None): | ||
130 | if name in self._registry: | ||
131 | del self._registry[name] | ||
132 | elif cls in self._registry.values(): | ||
133 | del self._registry[cls.name] | ||
134 | else: | ||
135 | logger.warning('Cannot unregister because no class or name given') | ||
136 | |||
137 | def get_backend_name(self, location): | ||
138 | """ | ||
139 | Return the name of the version control backend if found at given | ||
140 | location, e.g. vcs.get_backend_name('/path/to/vcs/checkout') | ||
141 | """ | ||
142 | for vc_type in self._registry.values(): | ||
143 | if vc_type.controls_location(location): | ||
144 | logger.debug('Determine that %s uses VCS: %s', | ||
145 | location, vc_type.name) | ||
146 | return vc_type.name | ||
147 | return None | ||
148 | |||
149 | def get_backend(self, name): | ||
150 | name = name.lower() | ||
151 | if name in self._registry: | ||
152 | return self._registry[name] | ||
153 | |||
154 | def get_backend_from_location(self, location): | ||
155 | vc_type = self.get_backend_name(location) | ||
156 | if vc_type: | ||
157 | return self.get_backend(vc_type) | ||
158 | return None | ||
159 | |||
160 | |||
161 | vcs = VcsSupport() | ||
162 | |||
163 | |||
164 | class VersionControl(object): | ||
165 | name = '' | ||
166 | dirname = '' | ||
167 | # List of supported schemes for this Version Control | ||
168 | schemes = () # type: Tuple[str, ...] | ||
169 | # Iterable of environment variable names to pass to call_subprocess(). | ||
170 | unset_environ = () # type: Tuple[str, ...] | ||
171 | default_arg_rev = None # type: Optional[str] | ||
172 | |||
173 | def __init__(self, url=None, *args, **kwargs): | ||
174 | self.url = url | ||
175 | super(VersionControl, self).__init__(*args, **kwargs) | ||
176 | |||
177 | def get_base_rev_args(self, rev): | ||
178 | """ | ||
179 | Return the base revision arguments for a vcs command. | ||
180 | |||
181 | Args: | ||
182 | rev: the name of a revision to install. Cannot be None. | ||
183 | """ | ||
184 | raise NotImplementedError | ||
185 | |||
186 | def make_rev_options(self, rev=None, extra_args=None): | ||
187 | """ | ||
188 | Return a RevOptions object. | ||
189 | |||
190 | Args: | ||
191 | rev: the name of a revision to install. | ||
192 | extra_args: a list of extra options. | ||
193 | """ | ||
194 | return RevOptions(self, rev, extra_args=extra_args) | ||
195 | |||
196 | def _is_local_repository(self, repo): | ||
197 | """ | ||
198 | posix absolute paths start with os.path.sep, | ||
199 | win32 ones start with drive (like c:\\folder) | ||
200 | """ | ||
201 | drive, tail = os.path.splitdrive(repo) | ||
202 | return repo.startswith(os.path.sep) or drive | ||
203 | |||
204 | # See issue #1083 for why this method was introduced: | ||
205 | # https://github.com/pypa/pip/issues/1083 | ||
206 | def translate_egg_surname(self, surname): | ||
207 | # For example, Django has branches of the form "stable/1.7.x". | ||
208 | return surname.replace('/', '_') | ||
209 | |||
210 | def export(self, location): | ||
211 | """ | ||
212 | Export the repository at the url to the destination location | ||
213 | i.e. only download the files, without vcs informations | ||
214 | """ | ||
215 | raise NotImplementedError | ||
216 | |||
217 | def get_url_rev(self): | ||
218 | """ | ||
219 | Returns the correct repository URL and revision by parsing the given | ||
220 | repository URL | ||
221 | """ | ||
222 | error_message = ( | ||
223 | "Sorry, '%s' is a malformed VCS url. " | ||
224 | "The format is <vcs>+<protocol>://<url>, " | ||
225 | "e.g. svn+http://myrepo/svn/MyApp#egg=MyApp" | ||
226 | ) | ||
227 | assert '+' in self.url, error_message % self.url | ||
228 | url = self.url.split('+', 1)[1] | ||
229 | scheme, netloc, path, query, frag = urllib_parse.urlsplit(url) | ||
230 | rev = None | ||
231 | if '@' in path: | ||
232 | path, rev = path.rsplit('@', 1) | ||
233 | url = urllib_parse.urlunsplit((scheme, netloc, path, query, '')) | ||
234 | return url, rev | ||
235 | |||
236 | def get_info(self, location): | ||
237 | """ | ||
238 | Returns (url, revision), where both are strings | ||
239 | """ | ||
240 | assert not location.rstrip('/').endswith(self.dirname), \ | ||
241 | 'Bad directory: %s' % location | ||
242 | return self.get_url(location), self.get_revision(location) | ||
243 | |||
244 | def normalize_url(self, url): | ||
245 | """ | ||
246 | Normalize a URL for comparison by unquoting it and removing any | ||
247 | trailing slash. | ||
248 | """ | ||
249 | return urllib_parse.unquote(url).rstrip('/') | ||
250 | |||
251 | def compare_urls(self, url1, url2): | ||
252 | """ | ||
253 | Compare two repo URLs for identity, ignoring incidental differences. | ||
254 | """ | ||
255 | return (self.normalize_url(url1) == self.normalize_url(url2)) | ||
256 | |||
257 | def obtain(self, dest): | ||
258 | """ | ||
259 | Called when installing or updating an editable package, takes the | ||
260 | source path of the checkout. | ||
261 | """ | ||
262 | raise NotImplementedError | ||
263 | |||
264 | def switch(self, dest, url, rev_options): | ||
265 | """ | ||
266 | Switch the repo at ``dest`` to point to ``URL``. | ||
267 | |||
268 | Args: | ||
269 | rev_options: a RevOptions object. | ||
270 | """ | ||
271 | raise NotImplementedError | ||
272 | |||
273 | def update(self, dest, rev_options): | ||
274 | """ | ||
275 | Update an already-existing repo to the given ``rev_options``. | ||
276 | |||
277 | Args: | ||
278 | rev_options: a RevOptions object. | ||
279 | """ | ||
280 | raise NotImplementedError | ||
281 | |||
282 | def is_commit_id_equal(self, dest, name): | ||
283 | """ | ||
284 | Return whether the id of the current commit equals the given name. | ||
285 | |||
286 | Args: | ||
287 | dest: the repository directory. | ||
288 | name: a string name. | ||
289 | """ | ||
290 | raise NotImplementedError | ||
291 | |||
292 | def check_destination(self, dest, url, rev_options): | ||
293 | """ | ||
294 | Prepare a location to receive a checkout/clone. | ||
295 | |||
296 | Return True if the location is ready for (and requires) a | ||
297 | checkout/clone, False otherwise. | ||
298 | |||
299 | Args: | ||
300 | rev_options: a RevOptions object. | ||
301 | """ | ||
302 | checkout = True | ||
303 | prompt = False | ||
304 | rev_display = rev_options.to_display() | ||
305 | if os.path.exists(dest): | ||
306 | checkout = False | ||
307 | if os.path.exists(os.path.join(dest, self.dirname)): | ||
308 | existing_url = self.get_url(dest) | ||
309 | if self.compare_urls(existing_url, url): | ||
310 | logger.debug( | ||
311 | '%s in %s exists, and has correct URL (%s)', | ||
312 | self.repo_name.title(), | ||
313 | display_path(dest), | ||
314 | url, | ||
315 | ) | ||
316 | if not self.is_commit_id_equal(dest, rev_options.rev): | ||
317 | logger.info( | ||
318 | 'Updating %s %s%s', | ||
319 | display_path(dest), | ||
320 | self.repo_name, | ||
321 | rev_display, | ||
322 | ) | ||
323 | self.update(dest, rev_options) | ||
324 | else: | ||
325 | logger.info( | ||
326 | 'Skipping because already up-to-date.') | ||
327 | else: | ||
328 | logger.warning( | ||
329 | '%s %s in %s exists with URL %s', | ||
330 | self.name, | ||
331 | self.repo_name, | ||
332 | display_path(dest), | ||
333 | existing_url, | ||
334 | ) | ||
335 | prompt = ('(s)witch, (i)gnore, (w)ipe, (b)ackup ', | ||
336 | ('s', 'i', 'w', 'b')) | ||
337 | else: | ||
338 | logger.warning( | ||
339 | 'Directory %s already exists, and is not a %s %s.', | ||
340 | dest, | ||
341 | self.name, | ||
342 | self.repo_name, | ||
343 | ) | ||
344 | prompt = ('(i)gnore, (w)ipe, (b)ackup ', ('i', 'w', 'b')) | ||
345 | if prompt: | ||
346 | logger.warning( | ||
347 | 'The plan is to install the %s repository %s', | ||
348 | self.name, | ||
349 | url, | ||
350 | ) | ||
351 | response = ask_path_exists('What to do? %s' % prompt[0], | ||
352 | prompt[1]) | ||
353 | |||
354 | if response == 's': | ||
355 | logger.info( | ||
356 | 'Switching %s %s to %s%s', | ||
357 | self.repo_name, | ||
358 | display_path(dest), | ||
359 | url, | ||
360 | rev_display, | ||
361 | ) | ||
362 | self.switch(dest, url, rev_options) | ||
363 | elif response == 'i': | ||
364 | # do nothing | ||
365 | pass | ||
366 | elif response == 'w': | ||
367 | logger.warning('Deleting %s', display_path(dest)) | ||
368 | rmtree(dest) | ||
369 | checkout = True | ||
370 | elif response == 'b': | ||
371 | dest_dir = backup_dir(dest) | ||
372 | logger.warning( | ||
373 | 'Backing up %s to %s', display_path(dest), dest_dir, | ||
374 | ) | ||
375 | shutil.move(dest, dest_dir) | ||
376 | checkout = True | ||
377 | elif response == 'a': | ||
378 | sys.exit(-1) | ||
379 | return checkout | ||
380 | |||
381 | def unpack(self, location): | ||
382 | """ | ||
383 | Clean up current location and download the url repository | ||
384 | (and vcs infos) into location | ||
385 | """ | ||
386 | if os.path.exists(location): | ||
387 | rmtree(location) | ||
388 | self.obtain(location) | ||
389 | |||
390 | def get_src_requirement(self, dist, location): | ||
391 | """ | ||
392 | Return a string representing the requirement needed to | ||
393 | redownload the files currently present in location, something | ||
394 | like: | ||
395 | {repository_url}@{revision}#egg={project_name}-{version_identifier} | ||
396 | """ | ||
397 | raise NotImplementedError | ||
398 | |||
399 | def get_url(self, location): | ||
400 | """ | ||
401 | Return the url used at location | ||
402 | Used in get_info or check_destination | ||
403 | """ | ||
404 | raise NotImplementedError | ||
405 | |||
406 | def get_revision(self, location): | ||
407 | """ | ||
408 | Return the current commit id of the files at the given location. | ||
409 | """ | ||
410 | raise NotImplementedError | ||
411 | |||
412 | def run_command(self, cmd, show_stdout=True, cwd=None, | ||
413 | on_returncode='raise', | ||
414 | command_desc=None, | ||
415 | extra_environ=None, spinner=None): | ||
416 | """ | ||
417 | Run a VCS subcommand | ||
418 | This is simply a wrapper around call_subprocess that adds the VCS | ||
419 | command name, and checks that the VCS is available | ||
420 | """ | ||
421 | cmd = [self.name] + cmd | ||
422 | try: | ||
423 | return call_subprocess(cmd, show_stdout, cwd, | ||
424 | on_returncode, | ||
425 | command_desc, extra_environ, | ||
426 | unset_environ=self.unset_environ, | ||
427 | spinner=spinner) | ||
428 | except OSError as e: | ||
429 | # errno.ENOENT = no such file or directory | ||
430 | # In other words, the VCS executable isn't available | ||
431 | if e.errno == errno.ENOENT: | ||
432 | raise BadCommand( | ||
433 | 'Cannot find command %r - do you have ' | ||
434 | '%r installed and in your ' | ||
435 | 'PATH?' % (self.name, self.name)) | ||
436 | else: | ||
437 | raise # re-raise exception if a different error occurred | ||
438 | |||
439 | @classmethod | ||
440 | def controls_location(cls, location): | ||
441 | """ | ||
442 | Check if a location is controlled by the vcs. | ||
443 | It is meant to be overridden to implement smarter detection | ||
444 | mechanisms for specific vcs. | ||
445 | """ | ||
446 | logger.debug('Checking in %s for %s (%s)...', | ||
447 | location, cls.dirname, cls.name) | ||
448 | path = os.path.join(location, cls.dirname) | ||
449 | return os.path.exists(path) | ||
450 | |||
451 | |||
452 | def get_src_requirement(dist, location): | ||
453 | version_control = vcs.get_backend_from_location(location) | ||
454 | if version_control: | ||
455 | try: | ||
456 | return version_control().get_src_requirement(dist, | ||
457 | location) | ||
458 | except BadCommand: | ||
459 | logger.warning( | ||
460 | 'cannot determine version of editable source in %s ' | ||
461 | '(%s command not found in path)', | ||
462 | location, | ||
463 | version_control.name, | ||
464 | ) | ||
465 | return dist.as_requirement() | ||
466 | logger.warning( | ||
467 | 'cannot determine version of editable source in %s (is not SVN ' | ||
468 | 'checkout, Git clone, Mercurial clone or Bazaar branch)', | ||
469 | location, | ||
470 | ) | ||
471 | return dist.as_requirement() | ||
diff --git a/venv/lib/python3.7/site-packages/pip-10.0.1-py3.7.egg/pip/_internal/vcs/bazaar.py b/venv/lib/python3.7/site-packages/pip-10.0.1-py3.7.egg/pip/_internal/vcs/bazaar.py new file mode 100644 index 0000000..6ed629a --- /dev/null +++ b/venv/lib/python3.7/site-packages/pip-10.0.1-py3.7.egg/pip/_internal/vcs/bazaar.py | |||
@@ -0,0 +1,113 @@ | |||
1 | from __future__ import absolute_import | ||
2 | |||
3 | import logging | ||
4 | import os | ||
5 | |||
6 | from pip._vendor.six.moves.urllib import parse as urllib_parse | ||
7 | |||
8 | from pip._internal.download import path_to_url | ||
9 | from pip._internal.utils.misc import display_path, rmtree | ||
10 | from pip._internal.utils.temp_dir import TempDirectory | ||
11 | from pip._internal.vcs import VersionControl, vcs | ||
12 | |||
13 | logger = logging.getLogger(__name__) | ||
14 | |||
15 | |||
16 | class Bazaar(VersionControl): | ||
17 | name = 'bzr' | ||
18 | dirname = '.bzr' | ||
19 | repo_name = 'branch' | ||
20 | schemes = ( | ||
21 | 'bzr', 'bzr+http', 'bzr+https', 'bzr+ssh', 'bzr+sftp', 'bzr+ftp', | ||
22 | 'bzr+lp', | ||
23 | ) | ||
24 | |||
25 | def __init__(self, url=None, *args, **kwargs): | ||
26 | super(Bazaar, self).__init__(url, *args, **kwargs) | ||
27 | # This is only needed for python <2.7.5 | ||
28 | # Register lp but do not expose as a scheme to support bzr+lp. | ||
29 | if getattr(urllib_parse, 'uses_fragment', None): | ||
30 | urllib_parse.uses_fragment.extend(['lp']) | ||
31 | |||
32 | def get_base_rev_args(self, rev): | ||
33 | return ['-r', rev] | ||
34 | |||
35 | def export(self, location): | ||
36 | """ | ||
37 | Export the Bazaar repository at the url to the destination location | ||
38 | """ | ||
39 | # Remove the location to make sure Bazaar can export it correctly | ||
40 | if os.path.exists(location): | ||
41 | rmtree(location) | ||
42 | |||
43 | with TempDirectory(kind="export") as temp_dir: | ||
44 | self.unpack(temp_dir.path) | ||
45 | |||
46 | self.run_command( | ||
47 | ['export', location], | ||
48 | cwd=temp_dir.path, show_stdout=False, | ||
49 | ) | ||
50 | |||
51 | def switch(self, dest, url, rev_options): | ||
52 | self.run_command(['switch', url], cwd=dest) | ||
53 | |||
54 | def update(self, dest, rev_options): | ||
55 | cmd_args = ['pull', '-q'] + rev_options.to_args() | ||
56 | self.run_command(cmd_args, cwd=dest) | ||
57 | |||
58 | def obtain(self, dest): | ||
59 | url, rev = self.get_url_rev() | ||
60 | rev_options = self.make_rev_options(rev) | ||
61 | if self.check_destination(dest, url, rev_options): | ||
62 | rev_display = rev_options.to_display() | ||
63 | logger.info( | ||
64 | 'Checking out %s%s to %s', | ||
65 | url, | ||
66 | rev_display, | ||
67 | display_path(dest), | ||
68 | ) | ||
69 | cmd_args = ['branch', '-q'] + rev_options.to_args() + [url, dest] | ||
70 | self.run_command(cmd_args) | ||
71 | |||
72 | def get_url_rev(self): | ||
73 | # hotfix the URL scheme after removing bzr+ from bzr+ssh:// readd it | ||
74 | url, rev = super(Bazaar, self).get_url_rev() | ||
75 | if url.startswith('ssh://'): | ||
76 | url = 'bzr+' + url | ||
77 | return url, rev | ||
78 | |||
79 | def get_url(self, location): | ||
80 | urls = self.run_command(['info'], show_stdout=False, cwd=location) | ||
81 | for line in urls.splitlines(): | ||
82 | line = line.strip() | ||
83 | for x in ('checkout of branch: ', | ||
84 | 'parent branch: '): | ||
85 | if line.startswith(x): | ||
86 | repo = line.split(x)[1] | ||
87 | if self._is_local_repository(repo): | ||
88 | return path_to_url(repo) | ||
89 | return repo | ||
90 | return None | ||
91 | |||
92 | def get_revision(self, location): | ||
93 | revision = self.run_command( | ||
94 | ['revno'], show_stdout=False, cwd=location, | ||
95 | ) | ||
96 | return revision.splitlines()[-1] | ||
97 | |||
98 | def get_src_requirement(self, dist, location): | ||
99 | repo = self.get_url(location) | ||
100 | if not repo: | ||
101 | return None | ||
102 | if not repo.lower().startswith('bzr:'): | ||
103 | repo = 'bzr+' + repo | ||
104 | egg_project_name = dist.egg_name().split('-', 1)[0] | ||
105 | current_rev = self.get_revision(location) | ||
106 | return '%s@%s#egg=%s' % (repo, current_rev, egg_project_name) | ||
107 | |||
108 | def is_commit_id_equal(self, dest, name): | ||
109 | """Always assume the versions don't match""" | ||
110 | return False | ||
111 | |||
112 | |||
113 | vcs.register(Bazaar) | ||
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) | ||
diff --git a/venv/lib/python3.7/site-packages/pip-10.0.1-py3.7.egg/pip/_internal/vcs/mercurial.py b/venv/lib/python3.7/site-packages/pip-10.0.1-py3.7.egg/pip/_internal/vcs/mercurial.py new file mode 100644 index 0000000..3936473 --- /dev/null +++ b/venv/lib/python3.7/site-packages/pip-10.0.1-py3.7.egg/pip/_internal/vcs/mercurial.py | |||
@@ -0,0 +1,105 @@ | |||
1 | from __future__ import absolute_import | ||
2 | |||
3 | import logging | ||
4 | import os | ||
5 | |||
6 | from pip._vendor.six.moves import configparser | ||
7 | |||
8 | from pip._internal.download import path_to_url | ||
9 | from pip._internal.utils.misc import display_path | ||
10 | from pip._internal.utils.temp_dir import TempDirectory | ||
11 | from pip._internal.vcs import VersionControl, vcs | ||
12 | |||
13 | logger = logging.getLogger(__name__) | ||
14 | |||
15 | |||
16 | class Mercurial(VersionControl): | ||
17 | name = 'hg' | ||
18 | dirname = '.hg' | ||
19 | repo_name = 'clone' | ||
20 | schemes = ('hg', 'hg+http', 'hg+https', 'hg+ssh', 'hg+static-http') | ||
21 | |||
22 | def get_base_rev_args(self, rev): | ||
23 | return [rev] | ||
24 | |||
25 | def export(self, location): | ||
26 | """Export the Hg repository at the url to the destination location""" | ||
27 | with TempDirectory(kind="export") as temp_dir: | ||
28 | self.unpack(temp_dir.path) | ||
29 | |||
30 | self.run_command( | ||
31 | ['archive', location], show_stdout=False, cwd=temp_dir.path | ||
32 | ) | ||
33 | |||
34 | def switch(self, dest, url, rev_options): | ||
35 | repo_config = os.path.join(dest, self.dirname, 'hgrc') | ||
36 | config = configparser.SafeConfigParser() | ||
37 | try: | ||
38 | config.read(repo_config) | ||
39 | config.set('paths', 'default', url) | ||
40 | with open(repo_config, 'w') as config_file: | ||
41 | config.write(config_file) | ||
42 | except (OSError, configparser.NoSectionError) as exc: | ||
43 | logger.warning( | ||
44 | 'Could not switch Mercurial repository to %s: %s', url, exc, | ||
45 | ) | ||
46 | else: | ||
47 | cmd_args = ['update', '-q'] + rev_options.to_args() | ||
48 | self.run_command(cmd_args, cwd=dest) | ||
49 | |||
50 | def update(self, dest, rev_options): | ||
51 | self.run_command(['pull', '-q'], cwd=dest) | ||
52 | cmd_args = ['update', '-q'] + rev_options.to_args() | ||
53 | self.run_command(cmd_args, cwd=dest) | ||
54 | |||
55 | def obtain(self, dest): | ||
56 | url, rev = self.get_url_rev() | ||
57 | rev_options = self.make_rev_options(rev) | ||
58 | if self.check_destination(dest, url, rev_options): | ||
59 | rev_display = rev_options.to_display() | ||
60 | logger.info( | ||
61 | 'Cloning hg %s%s to %s', | ||
62 | url, | ||
63 | rev_display, | ||
64 | display_path(dest), | ||
65 | ) | ||
66 | self.run_command(['clone', '--noupdate', '-q', url, dest]) | ||
67 | cmd_args = ['update', '-q'] + rev_options.to_args() | ||
68 | self.run_command(cmd_args, cwd=dest) | ||
69 | |||
70 | def get_url(self, location): | ||
71 | url = self.run_command( | ||
72 | ['showconfig', 'paths.default'], | ||
73 | show_stdout=False, cwd=location).strip() | ||
74 | if self._is_local_repository(url): | ||
75 | url = path_to_url(url) | ||
76 | return url.strip() | ||
77 | |||
78 | def get_revision(self, location): | ||
79 | current_revision = self.run_command( | ||
80 | ['parents', '--template={rev}'], | ||
81 | show_stdout=False, cwd=location).strip() | ||
82 | return current_revision | ||
83 | |||
84 | def get_revision_hash(self, location): | ||
85 | current_rev_hash = self.run_command( | ||
86 | ['parents', '--template={node}'], | ||
87 | show_stdout=False, cwd=location).strip() | ||
88 | return current_rev_hash | ||
89 | |||
90 | def get_src_requirement(self, dist, location): | ||
91 | repo = self.get_url(location) | ||
92 | if not repo.lower().startswith('hg:'): | ||
93 | repo = 'hg+' + repo | ||
94 | egg_project_name = dist.egg_name().split('-', 1)[0] | ||
95 | if not repo: | ||
96 | return None | ||
97 | current_rev_hash = self.get_revision_hash(location) | ||
98 | return '%s@%s#egg=%s' % (repo, current_rev_hash, egg_project_name) | ||
99 | |||
100 | def is_commit_id_equal(self, dest, name): | ||
101 | """Always assume the versions don't match""" | ||
102 | return False | ||
103 | |||
104 | |||
105 | vcs.register(Mercurial) | ||
diff --git a/venv/lib/python3.7/site-packages/pip-10.0.1-py3.7.egg/pip/_internal/vcs/subversion.py b/venv/lib/python3.7/site-packages/pip-10.0.1-py3.7.egg/pip/_internal/vcs/subversion.py new file mode 100644 index 0000000..95e5440 --- /dev/null +++ b/venv/lib/python3.7/site-packages/pip-10.0.1-py3.7.egg/pip/_internal/vcs/subversion.py | |||
@@ -0,0 +1,271 @@ | |||
1 | from __future__ import absolute_import | ||
2 | |||
3 | import logging | ||
4 | import os | ||
5 | import re | ||
6 | |||
7 | from pip._vendor.six.moves.urllib import parse as urllib_parse | ||
8 | |||
9 | from pip._internal.index import Link | ||
10 | from pip._internal.utils.logging import indent_log | ||
11 | from pip._internal.utils.misc import display_path, rmtree | ||
12 | from pip._internal.vcs import VersionControl, vcs | ||
13 | |||
14 | _svn_xml_url_re = re.compile('url="([^"]+)"') | ||
15 | _svn_rev_re = re.compile(r'committed-rev="(\d+)"') | ||
16 | _svn_url_re = re.compile(r'URL: (.+)') | ||
17 | _svn_revision_re = re.compile(r'Revision: (.+)') | ||
18 | _svn_info_xml_rev_re = re.compile(r'\s*revision="(\d+)"') | ||
19 | _svn_info_xml_url_re = re.compile(r'<url>(.*)</url>') | ||
20 | |||
21 | |||
22 | logger = logging.getLogger(__name__) | ||
23 | |||
24 | |||
25 | class Subversion(VersionControl): | ||
26 | name = 'svn' | ||
27 | dirname = '.svn' | ||
28 | repo_name = 'checkout' | ||
29 | schemes = ('svn', 'svn+ssh', 'svn+http', 'svn+https', 'svn+svn') | ||
30 | |||
31 | def get_base_rev_args(self, rev): | ||
32 | return ['-r', rev] | ||
33 | |||
34 | def get_info(self, location): | ||
35 | """Returns (url, revision), where both are strings""" | ||
36 | assert not location.rstrip('/').endswith(self.dirname), \ | ||
37 | 'Bad directory: %s' % location | ||
38 | output = self.run_command( | ||
39 | ['info', location], | ||
40 | show_stdout=False, | ||
41 | extra_environ={'LANG': 'C'}, | ||
42 | ) | ||
43 | match = _svn_url_re.search(output) | ||
44 | if not match: | ||
45 | logger.warning( | ||
46 | 'Cannot determine URL of svn checkout %s', | ||
47 | display_path(location), | ||
48 | ) | ||
49 | logger.debug('Output that cannot be parsed: \n%s', output) | ||
50 | return None, None | ||
51 | url = match.group(1).strip() | ||
52 | match = _svn_revision_re.search(output) | ||
53 | if not match: | ||
54 | logger.warning( | ||
55 | 'Cannot determine revision of svn checkout %s', | ||
56 | display_path(location), | ||
57 | ) | ||
58 | logger.debug('Output that cannot be parsed: \n%s', output) | ||
59 | return url, None | ||
60 | return url, match.group(1) | ||
61 | |||
62 | def export(self, location): | ||
63 | """Export the svn repository at the url to the destination location""" | ||
64 | url, rev = self.get_url_rev() | ||
65 | rev_options = get_rev_options(self, url, rev) | ||
66 | url = self.remove_auth_from_url(url) | ||
67 | logger.info('Exporting svn repository %s to %s', url, location) | ||
68 | with indent_log(): | ||
69 | if os.path.exists(location): | ||
70 | # Subversion doesn't like to check out over an existing | ||
71 | # directory --force fixes this, but was only added in svn 1.5 | ||
72 | rmtree(location) | ||
73 | cmd_args = ['export'] + rev_options.to_args() + [url, location] | ||
74 | self.run_command(cmd_args, show_stdout=False) | ||
75 | |||
76 | def switch(self, dest, url, rev_options): | ||
77 | cmd_args = ['switch'] + rev_options.to_args() + [url, dest] | ||
78 | self.run_command(cmd_args) | ||
79 | |||
80 | def update(self, dest, rev_options): | ||
81 | cmd_args = ['update'] + rev_options.to_args() + [dest] | ||
82 | self.run_command(cmd_args) | ||
83 | |||
84 | def obtain(self, dest): | ||
85 | url, rev = self.get_url_rev() | ||
86 | rev_options = get_rev_options(self, url, rev) | ||
87 | url = self.remove_auth_from_url(url) | ||
88 | if self.check_destination(dest, url, rev_options): | ||
89 | rev_display = rev_options.to_display() | ||
90 | logger.info( | ||
91 | 'Checking out %s%s to %s', | ||
92 | url, | ||
93 | rev_display, | ||
94 | display_path(dest), | ||
95 | ) | ||
96 | cmd_args = ['checkout', '-q'] + rev_options.to_args() + [url, dest] | ||
97 | self.run_command(cmd_args) | ||
98 | |||
99 | def get_location(self, dist, dependency_links): | ||
100 | for url in dependency_links: | ||
101 | egg_fragment = Link(url).egg_fragment | ||
102 | if not egg_fragment: | ||
103 | continue | ||
104 | if '-' in egg_fragment: | ||
105 | # FIXME: will this work when a package has - in the name? | ||
106 | key = '-'.join(egg_fragment.split('-')[:-1]).lower() | ||
107 | else: | ||
108 | key = egg_fragment | ||
109 | if key == dist.key: | ||
110 | return url.split('#', 1)[0] | ||
111 | return None | ||
112 | |||
113 | def get_revision(self, location): | ||
114 | """ | ||
115 | Return the maximum revision for all files under a given location | ||
116 | """ | ||
117 | # Note: taken from setuptools.command.egg_info | ||
118 | revision = 0 | ||
119 | |||
120 | for base, dirs, files in os.walk(location): | ||
121 | if self.dirname not in dirs: | ||
122 | dirs[:] = [] | ||
123 | continue # no sense walking uncontrolled subdirs | ||
124 | dirs.remove(self.dirname) | ||
125 | entries_fn = os.path.join(base, self.dirname, 'entries') | ||
126 | if not os.path.exists(entries_fn): | ||
127 | # FIXME: should we warn? | ||
128 | continue | ||
129 | |||
130 | dirurl, localrev = self._get_svn_url_rev(base) | ||
131 | |||
132 | if base == location: | ||
133 | base = dirurl + '/' # save the root url | ||
134 | elif not dirurl or not dirurl.startswith(base): | ||
135 | dirs[:] = [] | ||
136 | continue # not part of the same svn tree, skip it | ||
137 | revision = max(revision, localrev) | ||
138 | return revision | ||
139 | |||
140 | def get_url_rev(self): | ||
141 | # hotfix the URL scheme after removing svn+ from svn+ssh:// readd it | ||
142 | url, rev = super(Subversion, self).get_url_rev() | ||
143 | if url.startswith('ssh://'): | ||
144 | url = 'svn+' + url | ||
145 | return url, rev | ||
146 | |||
147 | def get_url(self, location): | ||
148 | # In cases where the source is in a subdirectory, not alongside | ||
149 | # setup.py we have to look up in the location until we find a real | ||
150 | # setup.py | ||
151 | orig_location = location | ||
152 | while not os.path.exists(os.path.join(location, 'setup.py')): | ||
153 | last_location = location | ||
154 | location = os.path.dirname(location) | ||
155 | if location == last_location: | ||
156 | # We've traversed up to the root of the filesystem without | ||
157 | # finding setup.py | ||
158 | logger.warning( | ||
159 | "Could not find setup.py for directory %s (tried all " | ||
160 | "parent directories)", | ||
161 | orig_location, | ||
162 | ) | ||
163 | return None | ||
164 | |||
165 | return self._get_svn_url_rev(location)[0] | ||
166 | |||
167 | def _get_svn_url_rev(self, location): | ||
168 | from pip._internal.exceptions import InstallationError | ||
169 | |||
170 | entries_path = os.path.join(location, self.dirname, 'entries') | ||
171 | if os.path.exists(entries_path): | ||
172 | with open(entries_path) as f: | ||
173 | data = f.read() | ||
174 | else: # subversion >= 1.7 does not have the 'entries' file | ||
175 | data = '' | ||
176 | |||
177 | if (data.startswith('8') or | ||
178 | data.startswith('9') or | ||
179 | data.startswith('10')): | ||
180 | data = list(map(str.splitlines, data.split('\n\x0c\n'))) | ||
181 | del data[0][0] # get rid of the '8' | ||
182 | url = data[0][3] | ||
183 | revs = [int(d[9]) for d in data if len(d) > 9 and d[9]] + [0] | ||
184 | elif data.startswith('<?xml'): | ||
185 | match = _svn_xml_url_re.search(data) | ||
186 | if not match: | ||
187 | raise ValueError('Badly formatted data: %r' % data) | ||
188 | url = match.group(1) # get repository URL | ||
189 | revs = [int(m.group(1)) for m in _svn_rev_re.finditer(data)] + [0] | ||
190 | else: | ||
191 | try: | ||
192 | # subversion >= 1.7 | ||
193 | xml = self.run_command( | ||
194 | ['info', '--xml', location], | ||
195 | show_stdout=False, | ||
196 | ) | ||
197 | url = _svn_info_xml_url_re.search(xml).group(1) | ||
198 | revs = [ | ||
199 | int(m.group(1)) for m in _svn_info_xml_rev_re.finditer(xml) | ||
200 | ] | ||
201 | except InstallationError: | ||
202 | url, revs = None, [] | ||
203 | |||
204 | if revs: | ||
205 | rev = max(revs) | ||
206 | else: | ||
207 | rev = 0 | ||
208 | |||
209 | return url, rev | ||
210 | |||
211 | def get_src_requirement(self, dist, location): | ||
212 | repo = self.get_url(location) | ||
213 | if repo is None: | ||
214 | return None | ||
215 | # FIXME: why not project name? | ||
216 | egg_project_name = dist.egg_name().split('-', 1)[0] | ||
217 | rev = self.get_revision(location) | ||
218 | return 'svn+%s@%s#egg=%s' % (repo, rev, egg_project_name) | ||
219 | |||
220 | def is_commit_id_equal(self, dest, name): | ||
221 | """Always assume the versions don't match""" | ||
222 | return False | ||
223 | |||
224 | @staticmethod | ||
225 | def remove_auth_from_url(url): | ||
226 | # Return a copy of url with 'username:password@' removed. | ||
227 | # username/pass params are passed to subversion through flags | ||
228 | # and are not recognized in the url. | ||
229 | |||
230 | # parsed url | ||
231 | purl = urllib_parse.urlsplit(url) | ||
232 | stripped_netloc = \ | ||
233 | purl.netloc.split('@')[-1] | ||
234 | |||
235 | # stripped url | ||
236 | url_pieces = ( | ||
237 | purl.scheme, stripped_netloc, purl.path, purl.query, purl.fragment | ||
238 | ) | ||
239 | surl = urllib_parse.urlunsplit(url_pieces) | ||
240 | return surl | ||
241 | |||
242 | |||
243 | def get_rev_options(vcs, url, rev): | ||
244 | """ | ||
245 | Return a RevOptions object. | ||
246 | """ | ||
247 | r = urllib_parse.urlsplit(url) | ||
248 | if hasattr(r, 'username'): | ||
249 | # >= Python-2.5 | ||
250 | username, password = r.username, r.password | ||
251 | else: | ||
252 | netloc = r[1] | ||
253 | if '@' in netloc: | ||
254 | auth = netloc.split('@')[0] | ||
255 | if ':' in auth: | ||
256 | username, password = auth.split(':', 1) | ||
257 | else: | ||
258 | username, password = auth, None | ||
259 | else: | ||
260 | username, password = None, None | ||
261 | |||
262 | extra_args = [] | ||
263 | if username: | ||
264 | extra_args += ['--username', username] | ||
265 | if password: | ||
266 | extra_args += ['--password', password] | ||
267 | |||
268 | return vcs.make_rev_options(rev, extra_args=extra_args) | ||
269 | |||
270 | |||
271 | vcs.register(Subversion) | ||