ruyi 0.39.0__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.
Files changed (101) hide show
  1. ruyi/__init__.py +21 -0
  2. ruyi/__main__.py +98 -0
  3. ruyi/cli/__init__.py +5 -0
  4. ruyi/cli/builtin_commands.py +14 -0
  5. ruyi/cli/cmd.py +224 -0
  6. ruyi/cli/completer.py +50 -0
  7. ruyi/cli/completion.py +26 -0
  8. ruyi/cli/config_cli.py +153 -0
  9. ruyi/cli/main.py +111 -0
  10. ruyi/cli/self_cli.py +295 -0
  11. ruyi/cli/user_input.py +127 -0
  12. ruyi/cli/version_cli.py +45 -0
  13. ruyi/config/__init__.py +401 -0
  14. ruyi/config/editor.py +92 -0
  15. ruyi/config/errors.py +76 -0
  16. ruyi/config/news.py +39 -0
  17. ruyi/config/schema.py +197 -0
  18. ruyi/device/__init__.py +0 -0
  19. ruyi/device/provision.py +591 -0
  20. ruyi/device/provision_cli.py +40 -0
  21. ruyi/log/__init__.py +272 -0
  22. ruyi/mux/.gitignore +1 -0
  23. ruyi/mux/__init__.py +0 -0
  24. ruyi/mux/runtime.py +213 -0
  25. ruyi/mux/venv/__init__.py +12 -0
  26. ruyi/mux/venv/emulator_cfg.py +41 -0
  27. ruyi/mux/venv/maker.py +782 -0
  28. ruyi/mux/venv/venv_cli.py +92 -0
  29. ruyi/mux/venv_cfg.py +214 -0
  30. ruyi/pluginhost/__init__.py +0 -0
  31. ruyi/pluginhost/api.py +206 -0
  32. ruyi/pluginhost/ctx.py +222 -0
  33. ruyi/pluginhost/paths.py +135 -0
  34. ruyi/pluginhost/plugin_cli.py +37 -0
  35. ruyi/pluginhost/unsandboxed.py +246 -0
  36. ruyi/py.typed +0 -0
  37. ruyi/resource_bundle/__init__.py +20 -0
  38. ruyi/resource_bundle/__main__.py +55 -0
  39. ruyi/resource_bundle/data.py +26 -0
  40. ruyi/ruyipkg/__init__.py +0 -0
  41. ruyi/ruyipkg/admin_checksum.py +88 -0
  42. ruyi/ruyipkg/admin_cli.py +83 -0
  43. ruyi/ruyipkg/atom.py +184 -0
  44. ruyi/ruyipkg/augmented_pkg.py +212 -0
  45. ruyi/ruyipkg/canonical_dump.py +320 -0
  46. ruyi/ruyipkg/checksum.py +39 -0
  47. ruyi/ruyipkg/cli_completion.py +42 -0
  48. ruyi/ruyipkg/distfile.py +208 -0
  49. ruyi/ruyipkg/entity.py +387 -0
  50. ruyi/ruyipkg/entity_cli.py +123 -0
  51. ruyi/ruyipkg/entity_provider.py +273 -0
  52. ruyi/ruyipkg/fetch.py +271 -0
  53. ruyi/ruyipkg/host.py +55 -0
  54. ruyi/ruyipkg/install.py +554 -0
  55. ruyi/ruyipkg/install_cli.py +150 -0
  56. ruyi/ruyipkg/list.py +126 -0
  57. ruyi/ruyipkg/list_cli.py +79 -0
  58. ruyi/ruyipkg/list_filter.py +173 -0
  59. ruyi/ruyipkg/msg.py +99 -0
  60. ruyi/ruyipkg/news.py +123 -0
  61. ruyi/ruyipkg/news_cli.py +78 -0
  62. ruyi/ruyipkg/news_store.py +183 -0
  63. ruyi/ruyipkg/pkg_manifest.py +657 -0
  64. ruyi/ruyipkg/profile.py +208 -0
  65. ruyi/ruyipkg/profile_cli.py +33 -0
  66. ruyi/ruyipkg/protocols.py +55 -0
  67. ruyi/ruyipkg/repo.py +763 -0
  68. ruyi/ruyipkg/state.py +345 -0
  69. ruyi/ruyipkg/unpack.py +369 -0
  70. ruyi/ruyipkg/unpack_method.py +91 -0
  71. ruyi/ruyipkg/update_cli.py +54 -0
  72. ruyi/telemetry/__init__.py +0 -0
  73. ruyi/telemetry/aggregate.py +72 -0
  74. ruyi/telemetry/event.py +41 -0
  75. ruyi/telemetry/node_info.py +192 -0
  76. ruyi/telemetry/provider.py +411 -0
  77. ruyi/telemetry/scope.py +43 -0
  78. ruyi/telemetry/store.py +238 -0
  79. ruyi/telemetry/telemetry_cli.py +127 -0
  80. ruyi/utils/__init__.py +0 -0
  81. ruyi/utils/ar.py +74 -0
  82. ruyi/utils/ci.py +63 -0
  83. ruyi/utils/frontmatter.py +38 -0
  84. ruyi/utils/git.py +169 -0
  85. ruyi/utils/global_mode.py +204 -0
  86. ruyi/utils/l10n.py +83 -0
  87. ruyi/utils/markdown.py +73 -0
  88. ruyi/utils/nuitka.py +33 -0
  89. ruyi/utils/porcelain.py +51 -0
  90. ruyi/utils/prereqs.py +77 -0
  91. ruyi/utils/ssl_patch.py +170 -0
  92. ruyi/utils/templating.py +34 -0
  93. ruyi/utils/toml.py +115 -0
  94. ruyi/utils/url.py +7 -0
  95. ruyi/utils/xdg_basedir.py +80 -0
  96. ruyi/version.py +67 -0
  97. ruyi-0.39.0.dist-info/LICENSE-Apache.txt +201 -0
  98. ruyi-0.39.0.dist-info/METADATA +403 -0
  99. ruyi-0.39.0.dist-info/RECORD +101 -0
  100. ruyi-0.39.0.dist-info/WHEEL +4 -0
  101. ruyi-0.39.0.dist-info/entry_points.txt +3 -0
@@ -0,0 +1,208 @@
1
+ from os import PathLike
2
+ from typing import Any, Iterable, TypeGuard, cast
3
+
4
+ from ..pluginhost.ctx import PluginHostContext, SupportsEvalFunction
5
+ from .pkg_manifest import EmulatorFlavor
6
+
7
+
8
+ class InvalidProfilePluginError(RuntimeError):
9
+ def __init__(self, s: str) -> None:
10
+ super().__init__(f"invalid arch profile plugin: {s}")
11
+
12
+
13
+ def validate_list_str(x: object) -> TypeGuard[list[str]]:
14
+ if not isinstance(x, list):
15
+ return False
16
+ x = cast(list[object], x)
17
+ return all(isinstance(y, str) for y in x)
18
+
19
+
20
+ def validate_list_str_or_none(x: object) -> TypeGuard[list[str] | None]:
21
+ return True if x is None else validate_list_str(x)
22
+
23
+
24
+ def validate_dict_str_str(x: object) -> TypeGuard[dict[str, str]]:
25
+ if not isinstance(x, dict):
26
+ return False
27
+ for k, v in cast(dict[object, object], x).items():
28
+ if not isinstance(k, str) or not isinstance(v, str):
29
+ return False
30
+ return True
31
+
32
+
33
+ class PluginProfileProvider:
34
+ def __init__(
35
+ self,
36
+ phctx: PluginHostContext[Any, SupportsEvalFunction],
37
+ plugin_id: str,
38
+ ) -> None:
39
+ self._phctx = phctx
40
+ self._plugin_id = plugin_id
41
+ self._ev = phctx.make_evaluator()
42
+
43
+ def _must_get(self, name: str) -> object:
44
+ if v := self._phctx.get_from_plugin(self._plugin_id, name):
45
+ return v
46
+ raise InvalidProfilePluginError(
47
+ f"'{name}' not found in plugin '{self._plugin_id}'"
48
+ )
49
+
50
+ def list_all_profile_ids(self) -> list[str]:
51
+ fn = self._must_get("list_all_profile_ids_v1")
52
+ ret = self._ev.eval_function(fn)
53
+ if not validate_list_str(ret):
54
+ raise InvalidProfilePluginError(
55
+ "list_all_profile_ids must return list[str]"
56
+ )
57
+
58
+ return ret
59
+
60
+ def list_needed_quirks(self, profile_id: str) -> list[str] | None:
61
+ # For backward compatibility, try "list_needed_quirks_v1" first, then
62
+ # fall back to "list_needed_flavors_v1" if the former is not available.
63
+ fn = self._phctx.get_from_plugin(self._plugin_id, "list_needed_quirks_v1")
64
+ if fn is None:
65
+ fn = self._must_get("list_needed_flavors_v1")
66
+
67
+ ret = self._ev.eval_function(fn, profile_id)
68
+ if not validate_list_str_or_none(ret):
69
+ raise InvalidProfilePluginError(
70
+ "list_needed_quirks_v1 must return list[str] | None"
71
+ )
72
+
73
+ return ret
74
+
75
+ def get_common_flags(self, profile_id: str, toolchain_quirks: list[str]) -> str:
76
+ result = self._maybe_get_common_flags_v2(profile_id, toolchain_quirks)
77
+ if result is not None:
78
+ return result
79
+ return self._get_common_flags_v1(profile_id)
80
+
81
+ def _get_common_flags_v1(self, profile_id: str) -> str:
82
+ fn = self._must_get("get_common_flags_v1")
83
+ ret = self._ev.eval_function(fn, profile_id)
84
+ if not isinstance(ret, str):
85
+ raise InvalidProfilePluginError("get_common_flags_v1 must return str")
86
+
87
+ return ret
88
+
89
+ def _maybe_get_common_flags_v2(
90
+ self,
91
+ profile_id: str,
92
+ toolchain_flavors: list[str],
93
+ ) -> str | None:
94
+ fn = self._phctx.get_from_plugin(self._plugin_id, "get_common_flags_v2")
95
+ if fn is None:
96
+ return None
97
+
98
+ ret = self._ev.eval_function(fn, profile_id, toolchain_flavors)
99
+ if not isinstance(ret, str):
100
+ raise InvalidProfilePluginError("get_common_flags_v2 must return str")
101
+
102
+ return ret
103
+
104
+ def get_needed_emulator_pkg_flavors(
105
+ self,
106
+ profile_id: str,
107
+ flavor: EmulatorFlavor,
108
+ ) -> Iterable[str]:
109
+ fn = self._must_get("get_needed_emulator_pkg_flavors_v1")
110
+ ret = self._ev.eval_function(
111
+ fn,
112
+ profile_id,
113
+ flavor,
114
+ )
115
+ if not validate_list_str(ret):
116
+ raise InvalidProfilePluginError(
117
+ "get_needed_emulator_pkg_flavors_v1 must return list[str]"
118
+ )
119
+
120
+ return ret
121
+
122
+ def check_emulator_flavor(
123
+ self,
124
+ profile_id: str,
125
+ flavor: EmulatorFlavor,
126
+ emulator_pkg_flavors: list[str] | None,
127
+ ) -> bool:
128
+ fn = self._must_get("check_emulator_flavor_v1")
129
+ ret = self._ev.eval_function(
130
+ fn,
131
+ profile_id,
132
+ flavor,
133
+ emulator_pkg_flavors,
134
+ )
135
+ if not isinstance(ret, bool):
136
+ raise InvalidProfilePluginError("check_emulator_flavor_v1 must return bool")
137
+
138
+ return ret
139
+
140
+ def get_env_config_for_emu_flavor(
141
+ self,
142
+ profile_id: str,
143
+ flavor: EmulatorFlavor,
144
+ sysroot: PathLike[Any] | None,
145
+ ) -> dict[str, str] | None:
146
+ fn = self._must_get("get_env_config_for_emu_flavor_v1")
147
+ ret = self._ev.eval_function(
148
+ fn,
149
+ profile_id,
150
+ flavor,
151
+ str(sysroot) if sysroot is not None else None,
152
+ )
153
+ if not validate_dict_str_str(ret):
154
+ raise InvalidProfilePluginError(
155
+ "get_env_config_for_emu_flavor_v1 must return dict[str, str]"
156
+ )
157
+
158
+ return ret
159
+
160
+
161
+ class ProfileProxy:
162
+ def __init__(
163
+ self,
164
+ provider: PluginProfileProvider,
165
+ arch: str,
166
+ profile_id: str,
167
+ ) -> None:
168
+ self._provider = provider
169
+ self._arch = arch
170
+ self._id = profile_id
171
+
172
+ @property
173
+ def arch(self) -> str:
174
+ return self._arch
175
+
176
+ @property
177
+ def id(self) -> str:
178
+ return self._id
179
+
180
+ @property
181
+ def need_quirks(self) -> set[str]:
182
+ r = self._provider.list_needed_quirks(self._id)
183
+ return set(r) if r else set()
184
+
185
+ def get_common_flags(self, toolchain_flavors: list[str]) -> str:
186
+ return self._provider.get_common_flags(self._id, toolchain_flavors)
187
+
188
+ def get_needed_emulator_pkg_flavors(
189
+ self,
190
+ flavor: EmulatorFlavor,
191
+ ) -> set[str]:
192
+ return set(self._provider.get_needed_emulator_pkg_flavors(self._id, flavor))
193
+
194
+ def check_emulator_flavor(
195
+ self,
196
+ flavor: EmulatorFlavor,
197
+ emulator_pkg_flavors: list[str] | None,
198
+ ) -> bool:
199
+ return self._provider.check_emulator_flavor(
200
+ self._id, flavor, emulator_pkg_flavors
201
+ )
202
+
203
+ def get_env_config_for_emu_flavor(
204
+ self,
205
+ flavor: EmulatorFlavor,
206
+ sysroot: PathLike[Any] | None,
207
+ ) -> dict[str, str] | None:
208
+ return self._provider.get_env_config_for_emu_flavor(self._id, flavor, sysroot)
@@ -0,0 +1,33 @@
1
+ import argparse
2
+ from typing import TYPE_CHECKING
3
+
4
+ from .list_cli import ListCommand
5
+
6
+ if TYPE_CHECKING:
7
+ from ..cli.completion import ArgumentParser
8
+ from ..config import GlobalConfig
9
+
10
+
11
+ class ListProfilesCommand(
12
+ ListCommand,
13
+ cmd="profiles",
14
+ help="List all available profiles",
15
+ ):
16
+ @classmethod
17
+ def configure_args(cls, gc: "GlobalConfig", p: "ArgumentParser") -> None:
18
+ pass
19
+
20
+ @classmethod
21
+ def main(cls, cfg: "GlobalConfig", args: argparse.Namespace) -> int:
22
+ logger = cfg.logger
23
+ mr = cfg.repo
24
+
25
+ for arch in mr.get_supported_arches():
26
+ for p in mr.iter_profiles_for_arch(arch):
27
+ if not p.need_quirks:
28
+ logger.stdout(p.id)
29
+ continue
30
+
31
+ logger.stdout(f"{p.id} (needs quirks: {p.need_quirks})")
32
+
33
+ return 0
@@ -0,0 +1,55 @@
1
+ from typing import Iterable, Protocol
2
+
3
+ from .pkg_manifest import BoundPackageManifest
4
+
5
+
6
+ class ProvidesPackageManifests(Protocol):
7
+ """A protocol that defines methods for providing package manifests."""
8
+
9
+ def get_pkg(
10
+ self,
11
+ name: str,
12
+ category: str,
13
+ ver: str,
14
+ ) -> BoundPackageManifest | None:
15
+ """Returns the package manifest by exact match, or None if not found."""
16
+ ...
17
+
18
+ def iter_pkg_manifests(self) -> Iterable[BoundPackageManifest]:
19
+ """Iterates over all package manifests provided by this store."""
20
+ ...
21
+
22
+ def iter_pkgs(
23
+ self,
24
+ ) -> Iterable[tuple[str, str, dict[str, BoundPackageManifest]]]:
25
+ """Iterates over all package manifests provided by this store, returning
26
+ ``(category, package_name, pkg_manifests_by_versions)``."""
27
+ ...
28
+
29
+ def iter_pkg_vers(
30
+ self,
31
+ name: str,
32
+ category: str | None = None,
33
+ ) -> Iterable[BoundPackageManifest]:
34
+ """Iterates over all versions of a certain package provided by this store,
35
+ specified by name and optionally category."""
36
+ ...
37
+
38
+ def get_pkg_latest_ver(
39
+ self,
40
+ name: str,
41
+ category: str | None = None,
42
+ include_prerelease_vers: bool = False,
43
+ ) -> BoundPackageManifest:
44
+ """Returns the latest version of a package provided by this store,
45
+ specified by name and optionally category.
46
+
47
+ If ``include_prerelease_vers`` is True, it will also consider prerelease
48
+ versions. Raises KeyError if no such package exists."""
49
+ ...
50
+
51
+ # To be removed later along with slug support
52
+ def get_pkg_by_slug(self, slug: str) -> BoundPackageManifest | None:
53
+ """Returns the package with the specified slug from this store, or None
54
+ if not found."""
55
+ ...