playground-ls-cli 4.14.1.dev8__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- localstack_cli/__init__.py +0 -0
- localstack_cli/cli/__init__.py +10 -0
- localstack_cli/cli/console.py +11 -0
- localstack_cli/cli/core_plugin.py +12 -0
- localstack_cli/cli/exceptions.py +19 -0
- localstack_cli/cli/localstack.py +951 -0
- localstack_cli/cli/lpm.py +138 -0
- localstack_cli/cli/main.py +22 -0
- localstack_cli/cli/plugin.py +39 -0
- localstack_cli/cli/plugins.py +134 -0
- localstack_cli/cli/profiles.py +65 -0
- localstack_cli/config.py +1689 -0
- localstack_cli/constants.py +165 -0
- localstack_cli/logging/__init__.py +0 -0
- localstack_cli/logging/format.py +194 -0
- localstack_cli/logging/setup.py +142 -0
- localstack_cli/packages/__init__.py +25 -0
- localstack_cli/packages/api.py +418 -0
- localstack_cli/packages/core.py +416 -0
- localstack_cli/pro/__init__.py +0 -0
- localstack_cli/pro/core/__init__.py +0 -0
- localstack_cli/pro/core/bootstrap/__init__.py +1 -0
- localstack_cli/pro/core/bootstrap/auth.py +213 -0
- localstack_cli/pro/core/bootstrap/dns_utils.py +55 -0
- localstack_cli/pro/core/bootstrap/entitlements.py +117 -0
- localstack_cli/pro/core/bootstrap/extensions/__init__.py +3 -0
- localstack_cli/pro/core/bootstrap/extensions/__main__.py +106 -0
- localstack_cli/pro/core/bootstrap/extensions/autoinstall.py +63 -0
- localstack_cli/pro/core/bootstrap/extensions/bootstrap.py +97 -0
- localstack_cli/pro/core/bootstrap/extensions/repository.py +374 -0
- localstack_cli/pro/core/bootstrap/licensingv2.py +1259 -0
- localstack_cli/pro/core/bootstrap/pods/__init__.py +0 -0
- localstack_cli/pro/core/bootstrap/pods/api_types.py +17 -0
- localstack_cli/pro/core/bootstrap/pods/constants.py +26 -0
- localstack_cli/pro/core/bootstrap/pods/remotes/__init__.py +0 -0
- localstack_cli/pro/core/bootstrap/pods/remotes/api.py +75 -0
- localstack_cli/pro/core/bootstrap/pods/remotes/configs.py +69 -0
- localstack_cli/pro/core/bootstrap/pods/remotes/params.py +86 -0
- localstack_cli/pro/core/bootstrap/pods_client.py +834 -0
- localstack_cli/pro/core/cli/__init__.py +0 -0
- localstack_cli/pro/core/cli/auth.py +226 -0
- localstack_cli/pro/core/cli/aws.py +16 -0
- localstack_cli/pro/core/cli/cli.py +99 -0
- localstack_cli/pro/core/cli/click_utils.py +21 -0
- localstack_cli/pro/core/cli/cloud_pods.py +465 -0
- localstack_cli/pro/core/cli/diff_view.py +41 -0
- localstack_cli/pro/core/cli/ephemeral.py +199 -0
- localstack_cli/pro/core/cli/extensions.py +492 -0
- localstack_cli/pro/core/cli/iam.py +180 -0
- localstack_cli/pro/core/cli/license.py +90 -0
- localstack_cli/pro/core/cli/localstack.py +118 -0
- localstack_cli/pro/core/cli/replicator.py +378 -0
- localstack_cli/pro/core/cli/state.py +183 -0
- localstack_cli/pro/core/cli/tree_view.py +235 -0
- localstack_cli/pro/core/config.py +556 -0
- localstack_cli/pro/core/constants.py +54 -0
- localstack_cli/pro/core/plugins.py +169 -0
- localstack_cli/runtime/__init__.py +6 -0
- localstack_cli/runtime/exceptions.py +7 -0
- localstack_cli/runtime/hooks.py +73 -0
- localstack_cli/testing/__init__.py +1 -0
- localstack_cli/testing/config.py +4 -0
- localstack_cli/utils/__init__.py +0 -0
- localstack_cli/utils/analytics/__init__.py +12 -0
- localstack_cli/utils/analytics/cli.py +67 -0
- localstack_cli/utils/analytics/client.py +111 -0
- localstack_cli/utils/analytics/events.py +30 -0
- localstack_cli/utils/analytics/logger.py +48 -0
- localstack_cli/utils/analytics/metadata.py +250 -0
- localstack_cli/utils/analytics/publisher.py +160 -0
- localstack_cli/utils/analytics/service_request_aggregator.py +133 -0
- localstack_cli/utils/archives.py +271 -0
- localstack_cli/utils/batching.py +258 -0
- localstack_cli/utils/bootstrap.py +1418 -0
- localstack_cli/utils/checksum.py +313 -0
- localstack_cli/utils/collections.py +554 -0
- localstack_cli/utils/common.py +229 -0
- localstack_cli/utils/container_networking.py +142 -0
- localstack_cli/utils/container_utils/__init__.py +0 -0
- localstack_cli/utils/container_utils/container_client.py +1585 -0
- localstack_cli/utils/container_utils/docker_cmd_client.py +987 -0
- localstack_cli/utils/container_utils/docker_sdk_client.py +1018 -0
- localstack_cli/utils/crypto.py +294 -0
- localstack_cli/utils/docker_utils.py +272 -0
- localstack_cli/utils/files.py +327 -0
- localstack_cli/utils/functions.py +92 -0
- localstack_cli/utils/http.py +326 -0
- localstack_cli/utils/json.py +219 -0
- localstack_cli/utils/net.py +516 -0
- localstack_cli/utils/no_exit_argument_parser.py +19 -0
- localstack_cli/utils/numbers.py +49 -0
- localstack_cli/utils/objects.py +235 -0
- localstack_cli/utils/patch.py +260 -0
- localstack_cli/utils/platform.py +77 -0
- localstack_cli/utils/run.py +514 -0
- localstack_cli/utils/server/__init__.py +0 -0
- localstack_cli/utils/server/tcp_proxy.py +108 -0
- localstack_cli/utils/serving.py +187 -0
- localstack_cli/utils/ssl.py +71 -0
- localstack_cli/utils/strings.py +245 -0
- localstack_cli/utils/sync.py +267 -0
- localstack_cli/utils/threads.py +163 -0
- localstack_cli/utils/time.py +81 -0
- localstack_cli/utils/urls.py +21 -0
- localstack_cli/utils/venv.py +100 -0
- localstack_cli/utils/xml.py +41 -0
- localstack_cli/version.py +34 -0
- playground_ls_cli-4.14.1.dev8.dist-info/METADATA +95 -0
- playground_ls_cli-4.14.1.dev8.dist-info/RECORD +112 -0
- playground_ls_cli-4.14.1.dev8.dist-info/WHEEL +5 -0
- playground_ls_cli-4.14.1.dev8.dist-info/entry_points.txt +17 -0
- playground_ls_cli-4.14.1.dev8.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,374 @@
|
|
|
1
|
+
import inspect
|
|
2
|
+
import logging
|
|
3
|
+
import os
|
|
4
|
+
import subprocess
|
|
5
|
+
from collections.abc import Generator
|
|
6
|
+
from pathlib import Path
|
|
7
|
+
from typing import Any, Literal, TypedDict
|
|
8
|
+
|
|
9
|
+
from localstack_cli import config, constants
|
|
10
|
+
from localstack_cli.utils.objects import singleton_factory
|
|
11
|
+
from localstack_cli.utils.venv import VirtualEnvironment
|
|
12
|
+
from plux import PluginManager
|
|
13
|
+
|
|
14
|
+
LOG = logging.getLogger(__name__)
|
|
15
|
+
|
|
16
|
+
LOCALSTACK_VENV = VirtualEnvironment(constants.LOCALSTACK_VENV_FOLDER)
|
|
17
|
+
|
|
18
|
+
VENV_DIRECTORY = "extensions/python_venv"
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
def get_extensions_venv() -> VirtualEnvironment:
|
|
22
|
+
"""
|
|
23
|
+
Returns a VirtualEnvironment object point to ``<var_libs>/extensions/python_venv``, either on the host
|
|
24
|
+
or in the container.
|
|
25
|
+
|
|
26
|
+
:return: the virtual environment
|
|
27
|
+
"""
|
|
28
|
+
return VirtualEnvironment(os.path.join(config.dirs.var_libs, VENV_DIRECTORY))
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
@singleton_factory
|
|
32
|
+
def get_extension_repository() -> "ExtensionsRepository":
|
|
33
|
+
"""
|
|
34
|
+
Returns the global ExtensionRepository and ensures that the localstack extension venv was created
|
|
35
|
+
correctly.
|
|
36
|
+
|
|
37
|
+
:return: an ExtensionsRepository instance
|
|
38
|
+
"""
|
|
39
|
+
return ExtensionsRepository(init_extension_venv())
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
def init_extension_venv() -> VirtualEnvironment:
|
|
43
|
+
"""
|
|
44
|
+
Idempotent operation to ensure the extensions virtual environment is created, and the localstack venv
|
|
45
|
+
is linked into it via a .pth file.
|
|
46
|
+
"""
|
|
47
|
+
venv = get_extensions_venv()
|
|
48
|
+
|
|
49
|
+
if not venv.exists:
|
|
50
|
+
LOG.info("initializing extension environment at %s", venv.venv_dir)
|
|
51
|
+
venv.create()
|
|
52
|
+
LOG.debug("adding localstack venv path %s to %s", LOCALSTACK_VENV, venv.venv_dir)
|
|
53
|
+
venv.add_pth("localstack-venv", LOCALSTACK_VENV)
|
|
54
|
+
|
|
55
|
+
return venv
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
def list_extension_metadata() -> list[dict]:
|
|
59
|
+
"""
|
|
60
|
+
Lists all available extensions and their distribution metadata.
|
|
61
|
+
|
|
62
|
+
:return: list of metadata documents
|
|
63
|
+
"""
|
|
64
|
+
from localstack_cli.extensions.api import Extension
|
|
65
|
+
|
|
66
|
+
return list_plugin_distribution_data(PluginManager(Extension.namespace))
|
|
67
|
+
|
|
68
|
+
|
|
69
|
+
def list_plugin_distribution_data(plugin_manager: PluginManager) -> list[dict]:
|
|
70
|
+
"""
|
|
71
|
+
Returns a list of dictionaries containing plugin metadata.
|
|
72
|
+
|
|
73
|
+
:param plugin_manager: the plugin manager holding the plugins
|
|
74
|
+
:return: a list of metadata documents
|
|
75
|
+
"""
|
|
76
|
+
metadata = []
|
|
77
|
+
|
|
78
|
+
for plugin in plugin_manager.list_containers():
|
|
79
|
+
try:
|
|
80
|
+
dist = plugin.distribution
|
|
81
|
+
except ValueError:
|
|
82
|
+
continue
|
|
83
|
+
except Exception as e:
|
|
84
|
+
LOG.error(
|
|
85
|
+
"Error while resolving distribution for plugin %s: %s. This probably means that the "
|
|
86
|
+
"package was removed or otherwise changed after the plugin was loaded. Restarting LocalStack "
|
|
87
|
+
"should fix the issue.",
|
|
88
|
+
plugin.name,
|
|
89
|
+
e,
|
|
90
|
+
)
|
|
91
|
+
continue
|
|
92
|
+
if not dist:
|
|
93
|
+
continue
|
|
94
|
+
|
|
95
|
+
spec = plugin.plugin_spec
|
|
96
|
+
module = inspect.getmodule(plugin.plugin_spec.factory)
|
|
97
|
+
|
|
98
|
+
doc = {
|
|
99
|
+
"namespace": spec.namespace,
|
|
100
|
+
"name": plugin.name,
|
|
101
|
+
"factory": {
|
|
102
|
+
"module": str(module.__name__),
|
|
103
|
+
"code": f"{module.__name__}.{spec.factory.__name__}",
|
|
104
|
+
"file": str(module.__file__),
|
|
105
|
+
},
|
|
106
|
+
"distribution": dist.metadata.json,
|
|
107
|
+
}
|
|
108
|
+
metadata.append(doc)
|
|
109
|
+
|
|
110
|
+
return metadata
|
|
111
|
+
|
|
112
|
+
|
|
113
|
+
class InstallerEvent(TypedDict, total=False):
|
|
114
|
+
event: Literal["status", "log", "error", "exception", "pip", "extension"]
|
|
115
|
+
message: str
|
|
116
|
+
extra: dict[str, Any] | None
|
|
117
|
+
|
|
118
|
+
|
|
119
|
+
class ExtensionsRepository:
|
|
120
|
+
"""
|
|
121
|
+
Helper class around a VirtualEnvironment that can install and uninstall packages into the venv.
|
|
122
|
+
"""
|
|
123
|
+
|
|
124
|
+
venv: VirtualEnvironment
|
|
125
|
+
|
|
126
|
+
def __init__(self, venv: VirtualEnvironment = None):
|
|
127
|
+
self.venv = venv or get_extensions_venv()
|
|
128
|
+
self.venv.inject_to_sys_path()
|
|
129
|
+
|
|
130
|
+
@property
|
|
131
|
+
def pip(self) -> Path:
|
|
132
|
+
"""
|
|
133
|
+
Returns the path to the pip binary within the virtual environment, or raises a FileNotFoundError if it
|
|
134
|
+
does not exist.
|
|
135
|
+
|
|
136
|
+
:raises FileNotFoundError: if the pip binary wasn't found
|
|
137
|
+
:return: a path
|
|
138
|
+
"""
|
|
139
|
+
# TODO: move to VirtualEnvironment
|
|
140
|
+
pip = self.venv.venv_dir / "bin" / "pip"
|
|
141
|
+
if not pip.exists():
|
|
142
|
+
raise FileNotFoundError(f"pip is not available at {self.pip}")
|
|
143
|
+
return pip
|
|
144
|
+
|
|
145
|
+
def pip_show(self, package: str) -> dict | None:
|
|
146
|
+
"""
|
|
147
|
+
Runs `pip show <package>` in the virtual environment and returns the output as a dictionary if the
|
|
148
|
+
package exist, or None if it doesn't exist.
|
|
149
|
+
|
|
150
|
+
:param package: the package to look up
|
|
151
|
+
:return: the metadata of the package or None
|
|
152
|
+
"""
|
|
153
|
+
# TODO: move to VirtualEnvironment
|
|
154
|
+
cmd = [self.pip, "show", package]
|
|
155
|
+
try:
|
|
156
|
+
output = subprocess.check_output(cmd, stderr=subprocess.STDOUT, text=True)
|
|
157
|
+
return dict(line.split(": ", maxsplit=1) for line in output.splitlines())
|
|
158
|
+
except subprocess.CalledProcessError as e:
|
|
159
|
+
if "not found" in e.output:
|
|
160
|
+
return None
|
|
161
|
+
raise
|
|
162
|
+
|
|
163
|
+
def run_install(self, name_or_url: str) -> Generator[InstallerEvent, None, None]:
|
|
164
|
+
"""
|
|
165
|
+
Creates a new installer generator to install the given package or URL. The ``name_or_url``
|
|
166
|
+
parameter is used directly as input for ``pip install``. The generator yields ``InstallerEvents``
|
|
167
|
+
as the installation procedure progresses.
|
|
168
|
+
|
|
169
|
+
:param name_or_url: the pypi package name or URL to install
|
|
170
|
+
:return: a generator
|
|
171
|
+
"""
|
|
172
|
+
cmd = [
|
|
173
|
+
self.pip,
|
|
174
|
+
"--no-input",
|
|
175
|
+
"--no-color",
|
|
176
|
+
"--disable-pip-version-check",
|
|
177
|
+
"install",
|
|
178
|
+
name_or_url,
|
|
179
|
+
]
|
|
180
|
+
|
|
181
|
+
yield {"event": "status", "message": "Checking installed extensions"}
|
|
182
|
+
|
|
183
|
+
metadata = self.pip_show(name_or_url)
|
|
184
|
+
if metadata:
|
|
185
|
+
name = metadata["Name"]
|
|
186
|
+
summary = metadata["Summary"]
|
|
187
|
+
author = metadata["Author"]
|
|
188
|
+
yield {
|
|
189
|
+
"event": "log",
|
|
190
|
+
"message": f"Extension {name} ({summary} by {author}) already installed",
|
|
191
|
+
}
|
|
192
|
+
return
|
|
193
|
+
|
|
194
|
+
# load extensions that are installed now
|
|
195
|
+
_clear_plugin_cache()
|
|
196
|
+
before = {item["name"]: item for item in list_extension_metadata()}
|
|
197
|
+
|
|
198
|
+
yield {"event": "status", "message": "Installing extension"}
|
|
199
|
+
|
|
200
|
+
not_found = False
|
|
201
|
+
try:
|
|
202
|
+
with SubprocessLineStream.open(cmd) as stream:
|
|
203
|
+
for line in stream:
|
|
204
|
+
yield {"event": "pip", "message": line}
|
|
205
|
+
if "No matching distribution found for" in line:
|
|
206
|
+
not_found = True
|
|
207
|
+
yield {
|
|
208
|
+
"event": "error",
|
|
209
|
+
"message": f"Could not resolve package {name_or_url}, please check the URL or "
|
|
210
|
+
"that the package exists in pypi.",
|
|
211
|
+
}
|
|
212
|
+
except subprocess.CalledProcessError:
|
|
213
|
+
if not_found:
|
|
214
|
+
return
|
|
215
|
+
raise
|
|
216
|
+
|
|
217
|
+
# re-load all extension metadata and compare to the ones that were installed
|
|
218
|
+
_clear_plugin_cache()
|
|
219
|
+
after = {item["name"]: item for item in list_extension_metadata()}
|
|
220
|
+
installed = [v for k, v in after.items() if k not in before]
|
|
221
|
+
|
|
222
|
+
if installed:
|
|
223
|
+
yield {"event": "log", "message": "Extension successfully installed"}
|
|
224
|
+
|
|
225
|
+
for extension in installed:
|
|
226
|
+
yield {"event": "extension", "message": "", "extra": extension}
|
|
227
|
+
else:
|
|
228
|
+
yield {"event": "log", "message": "No change"}
|
|
229
|
+
|
|
230
|
+
yield {"event": "status", "message": "Extension installation completed"}
|
|
231
|
+
|
|
232
|
+
def run_uninstall(self, package: str) -> Generator[InstallerEvent, None, None]:
|
|
233
|
+
"""
|
|
234
|
+
Like ``run_install``, only it performs a ``pip uninstall`` operation.
|
|
235
|
+
|
|
236
|
+
:param package: the package name
|
|
237
|
+
:return: a InstallerEvent generator
|
|
238
|
+
"""
|
|
239
|
+
cmd = [
|
|
240
|
+
self.pip,
|
|
241
|
+
"--no-input",
|
|
242
|
+
"--no-color",
|
|
243
|
+
"--disable-pip-version-check",
|
|
244
|
+
"uninstall",
|
|
245
|
+
"-y",
|
|
246
|
+
package,
|
|
247
|
+
]
|
|
248
|
+
|
|
249
|
+
yield {"event": "status", "message": "Checking extensions"}
|
|
250
|
+
|
|
251
|
+
metadata = self.pip_show(package)
|
|
252
|
+
if not metadata:
|
|
253
|
+
yield {"event": "log", "message": f"Extension {package} is not installed"}
|
|
254
|
+
return
|
|
255
|
+
|
|
256
|
+
name = metadata["Name"]
|
|
257
|
+
summary = metadata["Summary"]
|
|
258
|
+
yield {
|
|
259
|
+
"event": "log",
|
|
260
|
+
"message": f"Uninstalling extension {name} ({summary})",
|
|
261
|
+
}
|
|
262
|
+
yield {"event": "status", "message": "Uninstalling extension"}
|
|
263
|
+
|
|
264
|
+
with SubprocessLineStream.open(cmd) as stream:
|
|
265
|
+
for line in stream:
|
|
266
|
+
yield {"event": "pip", "message": line}
|
|
267
|
+
|
|
268
|
+
yield {"event": "log", "message": "Extension successfully uninstalled"}
|
|
269
|
+
_clear_plugin_cache()
|
|
270
|
+
yield {"event": "status", "message": "Extension uninstall completed"}
|
|
271
|
+
|
|
272
|
+
|
|
273
|
+
class SubprocessLineStream:
|
|
274
|
+
"""
|
|
275
|
+
Class to help with the pattern of streaming the output of a subprocess line-by-line. A
|
|
276
|
+
SubprocessLineStream can be closed which will terminate the underlying process. The stream will
|
|
277
|
+
automatically wait for and terminate the command after EOF is reached. It also automatically detects
|
|
278
|
+
text mode and rstrips newlines.
|
|
279
|
+
|
|
280
|
+
TODO: move into run utils in LocalStack
|
|
281
|
+
|
|
282
|
+
Best enjoyed as follows::
|
|
283
|
+
|
|
284
|
+
with SubprocessLineStream.open(["cowsay", "hello"]) as stream:
|
|
285
|
+
for line in stream:
|
|
286
|
+
print("|", line)
|
|
287
|
+
|
|
288
|
+
print(stream.process.returncode)
|
|
289
|
+
|
|
290
|
+
Will print::
|
|
291
|
+
|
|
292
|
+
| _______
|
|
293
|
+
| < hello >
|
|
294
|
+
| -------
|
|
295
|
+
| \\ ^__^
|
|
296
|
+
| \\ (oo)\\_______
|
|
297
|
+
| (__)\\ )\\/\
|
|
298
|
+
| ||----w |
|
|
299
|
+
| || ||
|
|
300
|
+
0
|
|
301
|
+
"""
|
|
302
|
+
|
|
303
|
+
default_timeout: int = 5
|
|
304
|
+
"""Time in seconds the stream will wait for the process output to finish before moving on."""
|
|
305
|
+
|
|
306
|
+
def __init__(self, process: subprocess.Popen):
|
|
307
|
+
self.process = process
|
|
308
|
+
|
|
309
|
+
def __iter__(self):
|
|
310
|
+
return self._gen()
|
|
311
|
+
|
|
312
|
+
def _gen(self):
|
|
313
|
+
stream = self.process.stdout
|
|
314
|
+
|
|
315
|
+
if self.process.text_mode:
|
|
316
|
+
newlines = "\r\n"
|
|
317
|
+
else:
|
|
318
|
+
newlines = b"\r\n"
|
|
319
|
+
|
|
320
|
+
for line in stream:
|
|
321
|
+
yield line.rstrip(newlines)
|
|
322
|
+
|
|
323
|
+
if self.process.wait(self.default_timeout) != 0:
|
|
324
|
+
raise subprocess.CalledProcessError(
|
|
325
|
+
returncode=self.process.returncode,
|
|
326
|
+
cmd=self.process.args,
|
|
327
|
+
)
|
|
328
|
+
|
|
329
|
+
def __enter__(self):
|
|
330
|
+
return self
|
|
331
|
+
|
|
332
|
+
def __exit__(self, exc_type, exc_val, exc_tb):
|
|
333
|
+
self.close()
|
|
334
|
+
|
|
335
|
+
def close(self):
|
|
336
|
+
self.process.terminate()
|
|
337
|
+
|
|
338
|
+
@classmethod
|
|
339
|
+
def open(cls, cmd, *args, **kwargs):
|
|
340
|
+
"""
|
|
341
|
+
Creates a new subprocess.Popen object with the given args with some sane defaults (mapping stderr to
|
|
342
|
+
stdout, and using text=True), wrapped in this class.
|
|
343
|
+
|
|
344
|
+
:param cmd: the command to run
|
|
345
|
+
:param args: args passed to subprocess.Popen
|
|
346
|
+
:param kwargs: keyword args passed to subprocess.Popen
|
|
347
|
+
:return:
|
|
348
|
+
"""
|
|
349
|
+
return cls(
|
|
350
|
+
subprocess.Popen(
|
|
351
|
+
cmd,
|
|
352
|
+
*args,
|
|
353
|
+
stdout=subprocess.PIPE,
|
|
354
|
+
stderr=subprocess.STDOUT,
|
|
355
|
+
text=True,
|
|
356
|
+
**kwargs,
|
|
357
|
+
)
|
|
358
|
+
)
|
|
359
|
+
|
|
360
|
+
|
|
361
|
+
def _clear_plugin_cache():
|
|
362
|
+
"""Clears the underlying caches used by plux to resolve entry points and distribution metadata."""
|
|
363
|
+
# FIXME: this is necessary to re-load the entrypoint cache when trying to resolve extension
|
|
364
|
+
# before/after install, but bad because it leaks internals.
|
|
365
|
+
from plux.runtime.cache import EntryPointsCache
|
|
366
|
+
from plux.runtime.metadata import packages_distributions
|
|
367
|
+
|
|
368
|
+
# plux cache that stores resolved entry points. this will force a re-calculation of the path hashing.
|
|
369
|
+
cache = EntryPointsCache.instance()
|
|
370
|
+
with cache._lock:
|
|
371
|
+
cache._cache.clear()
|
|
372
|
+
|
|
373
|
+
# plux cache that stores distribution data from importlib.metadata
|
|
374
|
+
packages_distributions.cache_clear()
|