Mercurial > repos > shellac > sam_consensus_v3
comparison env/lib/python3.9/site-packages/virtualenv/seed/embed/via_app_data/via_app_data.py @ 0:4f3585e2f14b draft default tip
"planemo upload commit 60cee0fc7c0cda8592644e1aad72851dec82c959"
author | shellac |
---|---|
date | Mon, 22 Mar 2021 18:12:50 +0000 |
parents | |
children |
comparison
equal
deleted
inserted
replaced
-1:000000000000 | 0:4f3585e2f14b |
---|---|
1 """Bootstrap""" | |
2 from __future__ import absolute_import, unicode_literals | |
3 | |
4 import logging | |
5 import sys | |
6 import traceback | |
7 from contextlib import contextmanager | |
8 from subprocess import CalledProcessError | |
9 from threading import Lock, Thread | |
10 | |
11 from virtualenv.info import fs_supports_symlink | |
12 from virtualenv.seed.embed.base_embed import BaseEmbed | |
13 from virtualenv.seed.wheels import get_wheel | |
14 from virtualenv.util.path import Path | |
15 | |
16 from .pip_install.copy import CopyPipInstall | |
17 from .pip_install.symlink import SymlinkPipInstall | |
18 | |
19 | |
20 class FromAppData(BaseEmbed): | |
21 def __init__(self, options): | |
22 super(FromAppData, self).__init__(options) | |
23 self.symlinks = options.symlink_app_data | |
24 | |
25 @classmethod | |
26 def add_parser_arguments(cls, parser, interpreter, app_data): | |
27 super(FromAppData, cls).add_parser_arguments(parser, interpreter, app_data) | |
28 can_symlink = app_data.transient is False and fs_supports_symlink() | |
29 parser.add_argument( | |
30 "--symlink-app-data", | |
31 dest="symlink_app_data", | |
32 action="store_true" if can_symlink else "store_false", | |
33 help="{} symlink the python packages from the app-data folder (requires seed pip>=19.3)".format( | |
34 "" if can_symlink else "not supported - ", | |
35 ), | |
36 default=False, | |
37 ) | |
38 | |
39 def run(self, creator): | |
40 if not self.enabled: | |
41 return | |
42 with self._get_seed_wheels(creator) as name_to_whl: | |
43 pip_version = name_to_whl["pip"].version_tuple if "pip" in name_to_whl else None | |
44 installer_class = self.installer_class(pip_version) | |
45 exceptions = {} | |
46 | |
47 def _install(name, wheel): | |
48 try: | |
49 logging.debug("install %s from wheel %s via %s", name, wheel, installer_class.__name__) | |
50 key = Path(installer_class.__name__) / wheel.path.stem | |
51 wheel_img = self.app_data.wheel_image(creator.interpreter.version_release_str, key) | |
52 installer = installer_class(wheel.path, creator, wheel_img) | |
53 parent = self.app_data.lock / wheel_img.parent | |
54 with parent.non_reentrant_lock_for_key(wheel_img.name): | |
55 if not installer.has_image(): | |
56 installer.build_image() | |
57 installer.install(creator.interpreter.version_info) | |
58 except Exception: # noqa | |
59 exceptions[name] = sys.exc_info() | |
60 | |
61 threads = list(Thread(target=_install, args=(n, w)) for n, w in name_to_whl.items()) | |
62 for thread in threads: | |
63 thread.start() | |
64 for thread in threads: | |
65 thread.join() | |
66 if exceptions: | |
67 messages = ["failed to build image {} because:".format(", ".join(exceptions.keys()))] | |
68 for value in exceptions.values(): | |
69 exc_type, exc_value, exc_traceback = value | |
70 messages.append("".join(traceback.format_exception(exc_type, exc_value, exc_traceback))) | |
71 raise RuntimeError("\n".join(messages)) | |
72 | |
73 @contextmanager | |
74 def _get_seed_wheels(self, creator): | |
75 name_to_whl, lock, fail = {}, Lock(), {} | |
76 | |
77 def _get(distribution, version): | |
78 for_py_version = creator.interpreter.version_release_str | |
79 failure, result = None, None | |
80 # fallback to download in case the exact version is not available | |
81 for download in [True] if self.download else [False, True]: | |
82 failure = None | |
83 try: | |
84 result = get_wheel( | |
85 distribution=distribution, | |
86 version=version, | |
87 for_py_version=for_py_version, | |
88 search_dirs=self.extra_search_dir, | |
89 download=download, | |
90 app_data=self.app_data, | |
91 do_periodic_update=self.periodic_update, | |
92 env=self.env, | |
93 ) | |
94 if result is not None: | |
95 break | |
96 except Exception as exception: # noqa | |
97 logging.exception("fail") | |
98 failure = exception | |
99 if failure: | |
100 if isinstance(failure, CalledProcessError): | |
101 msg = "failed to download {}".format(distribution) | |
102 if version is not None: | |
103 msg += " version {}".format(version) | |
104 msg += ", pip download exit code {}".format(failure.returncode) | |
105 output = failure.output if sys.version_info < (3, 5) else (failure.output + failure.stderr) | |
106 if output: | |
107 msg += "\n" | |
108 msg += output | |
109 else: | |
110 msg = repr(failure) | |
111 logging.error(msg) | |
112 with lock: | |
113 fail[distribution] = version | |
114 else: | |
115 with lock: | |
116 name_to_whl[distribution] = result | |
117 | |
118 threads = list( | |
119 Thread(target=_get, args=(distribution, version)) | |
120 for distribution, version in self.distribution_to_versions().items() | |
121 ) | |
122 for thread in threads: | |
123 thread.start() | |
124 for thread in threads: | |
125 thread.join() | |
126 if fail: | |
127 raise RuntimeError("seed failed due to failing to download wheels {}".format(", ".join(fail.keys()))) | |
128 yield name_to_whl | |
129 | |
130 def installer_class(self, pip_version_tuple): | |
131 if self.symlinks and pip_version_tuple: | |
132 # symlink support requires pip 19.3+ | |
133 if pip_version_tuple >= (19, 3): | |
134 return SymlinkPipInstall | |
135 return CopyPipInstall | |
136 | |
137 def __unicode__(self): | |
138 base = super(FromAppData, self).__unicode__() | |
139 msg = ", via={}, app_data_dir={}".format("symlink" if self.symlinks else "copy", self.app_data) | |
140 return base[:-1] + msg + base[-1] |