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]