ruyi 0.43.0a20251017__tar.gz → 0.44.0__tar.gz

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 (102) hide show
  1. {ruyi-0.43.0a20251017 → ruyi-0.44.0}/PKG-INFO +6 -3
  2. {ruyi-0.43.0a20251017 → ruyi-0.44.0}/README.md +2 -1
  3. {ruyi-0.43.0a20251017 → ruyi-0.44.0}/pyproject.toml +4 -2
  4. {ruyi-0.43.0a20251017 → ruyi-0.44.0}/ruyi/cli/main.py +20 -13
  5. {ruyi-0.43.0a20251017 → ruyi-0.44.0}/ruyi/cli/oobe.py +3 -7
  6. {ruyi-0.43.0a20251017 → ruyi-0.44.0}/ruyi/cli/self_cli.py +1 -2
  7. {ruyi-0.43.0a20251017 → ruyi-0.44.0}/ruyi/config/__init__.py +4 -8
  8. {ruyi-0.43.0a20251017 → ruyi-0.44.0}/ruyi/mux/venv/maker.py +52 -2
  9. {ruyi-0.43.0a20251017 → ruyi-0.44.0}/ruyi/pluginhost/unsandboxed.py +1 -1
  10. {ruyi-0.43.0a20251017 → ruyi-0.44.0}/ruyi/resource_bundle/data.py +1 -1
  11. {ruyi-0.43.0a20251017 → ruyi-0.44.0}/ruyi/ruyipkg/install.py +20 -22
  12. {ruyi-0.43.0a20251017 → ruyi-0.44.0}/ruyi/telemetry/aggregate.py +5 -0
  13. {ruyi-0.43.0a20251017 → ruyi-0.44.0}/ruyi/telemetry/provider.py +229 -87
  14. {ruyi-0.43.0a20251017 → ruyi-0.44.0}/ruyi/telemetry/store.py +68 -15
  15. {ruyi-0.43.0a20251017 → ruyi-0.44.0}/ruyi/telemetry/telemetry_cli.py +23 -5
  16. ruyi-0.44.0/ruyi/utils/__init__.py +0 -0
  17. {ruyi-0.43.0a20251017 → ruyi-0.44.0}/ruyi/version.py +1 -1
  18. ruyi-0.43.0a20251017/ruyi/mux/venv/__init__.py +0 -12
  19. {ruyi-0.43.0a20251017 → ruyi-0.44.0}/LICENSE-Apache.txt +0 -0
  20. {ruyi-0.43.0a20251017 → ruyi-0.44.0}/ruyi/__init__.py +0 -0
  21. {ruyi-0.43.0a20251017 → ruyi-0.44.0}/ruyi/__main__.py +0 -0
  22. {ruyi-0.43.0a20251017 → ruyi-0.44.0}/ruyi/cli/__init__.py +0 -0
  23. {ruyi-0.43.0a20251017 → ruyi-0.44.0}/ruyi/cli/builtin_commands.py +0 -0
  24. {ruyi-0.43.0a20251017 → ruyi-0.44.0}/ruyi/cli/cmd.py +0 -0
  25. {ruyi-0.43.0a20251017 → ruyi-0.44.0}/ruyi/cli/completer.py +0 -0
  26. {ruyi-0.43.0a20251017 → ruyi-0.44.0}/ruyi/cli/completion.py +0 -0
  27. {ruyi-0.43.0a20251017 → ruyi-0.44.0}/ruyi/cli/config_cli.py +0 -0
  28. {ruyi-0.43.0a20251017 → ruyi-0.44.0}/ruyi/cli/user_input.py +0 -0
  29. {ruyi-0.43.0a20251017 → ruyi-0.44.0}/ruyi/cli/version_cli.py +0 -0
  30. {ruyi-0.43.0a20251017 → ruyi-0.44.0}/ruyi/config/editor.py +0 -0
  31. {ruyi-0.43.0a20251017 → ruyi-0.44.0}/ruyi/config/errors.py +0 -0
  32. {ruyi-0.43.0a20251017 → ruyi-0.44.0}/ruyi/config/news.py +0 -0
  33. {ruyi-0.43.0a20251017 → ruyi-0.44.0}/ruyi/config/schema.py +0 -0
  34. {ruyi-0.43.0a20251017 → ruyi-0.44.0}/ruyi/device/__init__.py +0 -0
  35. {ruyi-0.43.0a20251017 → ruyi-0.44.0}/ruyi/device/provision.py +0 -0
  36. {ruyi-0.43.0a20251017 → ruyi-0.44.0}/ruyi/device/provision_cli.py +0 -0
  37. {ruyi-0.43.0a20251017 → ruyi-0.44.0}/ruyi/log/__init__.py +0 -0
  38. {ruyi-0.43.0a20251017 → ruyi-0.44.0}/ruyi/mux/__init__.py +0 -0
  39. {ruyi-0.43.0a20251017 → ruyi-0.44.0}/ruyi/mux/runtime.py +0 -0
  40. {ruyi-0.43.0a20251017/ruyi/pluginhost → ruyi-0.44.0/ruyi/mux/venv}/__init__.py +0 -0
  41. {ruyi-0.43.0a20251017 → ruyi-0.44.0}/ruyi/mux/venv/emulator_cfg.py +0 -0
  42. {ruyi-0.43.0a20251017 → ruyi-0.44.0}/ruyi/mux/venv/venv_cli.py +0 -0
  43. {ruyi-0.43.0a20251017 → ruyi-0.44.0}/ruyi/mux/venv_cfg.py +0 -0
  44. {ruyi-0.43.0a20251017/ruyi/ruyipkg → ruyi-0.44.0/ruyi/pluginhost}/__init__.py +0 -0
  45. {ruyi-0.43.0a20251017 → ruyi-0.44.0}/ruyi/pluginhost/api.py +0 -0
  46. {ruyi-0.43.0a20251017 → ruyi-0.44.0}/ruyi/pluginhost/ctx.py +0 -0
  47. {ruyi-0.43.0a20251017 → ruyi-0.44.0}/ruyi/pluginhost/paths.py +0 -0
  48. {ruyi-0.43.0a20251017 → ruyi-0.44.0}/ruyi/pluginhost/plugin_cli.py +0 -0
  49. {ruyi-0.43.0a20251017 → ruyi-0.44.0}/ruyi/py.typed +0 -0
  50. {ruyi-0.43.0a20251017 → ruyi-0.44.0}/ruyi/resource_bundle/__init__.py +0 -0
  51. {ruyi-0.43.0a20251017 → ruyi-0.44.0}/ruyi/resource_bundle/__main__.py +0 -0
  52. {ruyi-0.43.0a20251017/ruyi/telemetry → ruyi-0.44.0/ruyi/ruyipkg}/__init__.py +0 -0
  53. {ruyi-0.43.0a20251017 → ruyi-0.44.0}/ruyi/ruyipkg/admin_checksum.py +0 -0
  54. {ruyi-0.43.0a20251017 → ruyi-0.44.0}/ruyi/ruyipkg/admin_cli.py +0 -0
  55. {ruyi-0.43.0a20251017 → ruyi-0.44.0}/ruyi/ruyipkg/atom.py +0 -0
  56. {ruyi-0.43.0a20251017 → ruyi-0.44.0}/ruyi/ruyipkg/augmented_pkg.py +0 -0
  57. {ruyi-0.43.0a20251017 → ruyi-0.44.0}/ruyi/ruyipkg/canonical_dump.py +0 -0
  58. {ruyi-0.43.0a20251017 → ruyi-0.44.0}/ruyi/ruyipkg/checksum.py +0 -0
  59. {ruyi-0.43.0a20251017 → ruyi-0.44.0}/ruyi/ruyipkg/cli_completion.py +0 -0
  60. {ruyi-0.43.0a20251017 → ruyi-0.44.0}/ruyi/ruyipkg/distfile.py +0 -0
  61. {ruyi-0.43.0a20251017 → ruyi-0.44.0}/ruyi/ruyipkg/entity.py +0 -0
  62. {ruyi-0.43.0a20251017 → ruyi-0.44.0}/ruyi/ruyipkg/entity_cli.py +0 -0
  63. {ruyi-0.43.0a20251017 → ruyi-0.44.0}/ruyi/ruyipkg/entity_provider.py +0 -0
  64. {ruyi-0.43.0a20251017 → ruyi-0.44.0}/ruyi/ruyipkg/fetcher.py +0 -0
  65. {ruyi-0.43.0a20251017 → ruyi-0.44.0}/ruyi/ruyipkg/host.py +0 -0
  66. {ruyi-0.43.0a20251017 → ruyi-0.44.0}/ruyi/ruyipkg/install_cli.py +0 -0
  67. {ruyi-0.43.0a20251017 → ruyi-0.44.0}/ruyi/ruyipkg/list.py +0 -0
  68. {ruyi-0.43.0a20251017 → ruyi-0.44.0}/ruyi/ruyipkg/list_cli.py +0 -0
  69. {ruyi-0.43.0a20251017 → ruyi-0.44.0}/ruyi/ruyipkg/list_filter.py +0 -0
  70. {ruyi-0.43.0a20251017 → ruyi-0.44.0}/ruyi/ruyipkg/msg.py +0 -0
  71. {ruyi-0.43.0a20251017 → ruyi-0.44.0}/ruyi/ruyipkg/news.py +0 -0
  72. {ruyi-0.43.0a20251017 → ruyi-0.44.0}/ruyi/ruyipkg/news_cli.py +0 -0
  73. {ruyi-0.43.0a20251017 → ruyi-0.44.0}/ruyi/ruyipkg/news_store.py +0 -0
  74. {ruyi-0.43.0a20251017 → ruyi-0.44.0}/ruyi/ruyipkg/pkg_manifest.py +0 -0
  75. {ruyi-0.43.0a20251017 → ruyi-0.44.0}/ruyi/ruyipkg/profile.py +0 -0
  76. {ruyi-0.43.0a20251017 → ruyi-0.44.0}/ruyi/ruyipkg/profile_cli.py +0 -0
  77. {ruyi-0.43.0a20251017 → ruyi-0.44.0}/ruyi/ruyipkg/protocols.py +0 -0
  78. {ruyi-0.43.0a20251017 → ruyi-0.44.0}/ruyi/ruyipkg/repo.py +0 -0
  79. {ruyi-0.43.0a20251017 → ruyi-0.44.0}/ruyi/ruyipkg/state.py +0 -0
  80. {ruyi-0.43.0a20251017 → ruyi-0.44.0}/ruyi/ruyipkg/unpack.py +0 -0
  81. {ruyi-0.43.0a20251017 → ruyi-0.44.0}/ruyi/ruyipkg/unpack_method.py +0 -0
  82. {ruyi-0.43.0a20251017 → ruyi-0.44.0}/ruyi/ruyipkg/update_cli.py +0 -0
  83. {ruyi-0.43.0a20251017/ruyi/utils → ruyi-0.44.0/ruyi/telemetry}/__init__.py +0 -0
  84. {ruyi-0.43.0a20251017 → ruyi-0.44.0}/ruyi/telemetry/event.py +0 -0
  85. {ruyi-0.43.0a20251017 → ruyi-0.44.0}/ruyi/telemetry/scope.py +0 -0
  86. {ruyi-0.43.0a20251017 → ruyi-0.44.0}/ruyi/utils/ar.py +0 -0
  87. {ruyi-0.43.0a20251017 → ruyi-0.44.0}/ruyi/utils/ci.py +0 -0
  88. {ruyi-0.43.0a20251017 → ruyi-0.44.0}/ruyi/utils/frontmatter.py +0 -0
  89. {ruyi-0.43.0a20251017 → ruyi-0.44.0}/ruyi/utils/git.py +0 -0
  90. {ruyi-0.43.0a20251017 → ruyi-0.44.0}/ruyi/utils/global_mode.py +0 -0
  91. {ruyi-0.43.0a20251017 → ruyi-0.44.0}/ruyi/utils/l10n.py +0 -0
  92. {ruyi-0.43.0a20251017 → ruyi-0.44.0}/ruyi/utils/markdown.py +0 -0
  93. {ruyi-0.43.0a20251017 → ruyi-0.44.0}/ruyi/utils/mounts.py +0 -0
  94. {ruyi-0.43.0a20251017 → ruyi-0.44.0}/ruyi/utils/node_info.py +0 -0
  95. {ruyi-0.43.0a20251017 → ruyi-0.44.0}/ruyi/utils/nuitka.py +0 -0
  96. {ruyi-0.43.0a20251017 → ruyi-0.44.0}/ruyi/utils/porcelain.py +0 -0
  97. {ruyi-0.43.0a20251017 → ruyi-0.44.0}/ruyi/utils/prereqs.py +0 -0
  98. {ruyi-0.43.0a20251017 → ruyi-0.44.0}/ruyi/utils/ssl_patch.py +0 -0
  99. {ruyi-0.43.0a20251017 → ruyi-0.44.0}/ruyi/utils/templating.py +0 -0
  100. {ruyi-0.43.0a20251017 → ruyi-0.44.0}/ruyi/utils/toml.py +0 -0
  101. {ruyi-0.43.0a20251017 → ruyi-0.44.0}/ruyi/utils/url.py +0 -0
  102. {ruyi-0.43.0a20251017 → ruyi-0.44.0}/ruyi/utils/xdg_basedir.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: ruyi
3
- Version: 0.43.0a20251017
3
+ Version: 0.44.0
4
4
  Summary: Package manager for RuyiSDK
5
5
  License: Apache License
6
6
  Version 2.0, January 2004
@@ -217,6 +217,7 @@ Classifier: Programming Language :: Python :: 3.10
217
217
  Classifier: Programming Language :: Python :: 3.11
218
218
  Classifier: Programming Language :: Python :: 3.12
219
219
  Classifier: Programming Language :: Python :: 3.13
220
+ Classifier: Programming Language :: Python :: 3.14
220
221
  Classifier: Topic :: Software Development :: Build Tools
221
222
  Classifier: Topic :: Software Development :: Embedded Systems
222
223
  Classifier: Topic :: System :: Software Distribution
@@ -225,7 +226,8 @@ Requires-Dist: argcomplete (>=2.0.0)
225
226
  Requires-Dist: arpy
226
227
  Requires-Dist: fastjsonschema (>=2.15.1)
227
228
  Requires-Dist: jinja2 (>=3,<4)
228
- Requires-Dist: pygit2 (>=1.6)
229
+ Requires-Dist: pygit2 (>=1.6) ; python_version >= "3.11"
230
+ Requires-Dist: pygit2 (>=1.6,<1.19) ; python_version < "3.11"
229
231
  Requires-Dist: pyyaml (>=5.4)
230
232
  Requires-Dist: requests (>=2,<3)
231
233
  Requires-Dist: rich (>=11.2.0)
@@ -406,7 +408,8 @@ described below.
406
408
  There are 3 telemetry modes available:
407
409
 
408
410
  * `local`: data will be collected but not uploaded without user action.
409
- * `off`: data will not be collected nor uploaded.
411
+ * `off`: data will neither be collected nor uploaded, except for a one-time
412
+ upload of `ruyi`'s version number on first run.
410
413
  * `on`: data will be collected and periodically uploaded.
411
414
 
412
415
  By default the `local` mode is active from `ruyi` 0.42.0 (inclusive) on, which
@@ -163,7 +163,8 @@ described below.
163
163
  There are 3 telemetry modes available:
164
164
 
165
165
  * `local`: data will be collected but not uploaded without user action.
166
- * `off`: data will not be collected nor uploaded.
166
+ * `off`: data will neither be collected nor uploaded, except for a one-time
167
+ upload of `ruyi`'s version number on first run.
167
168
  * `on`: data will be collected and periodically uploaded.
168
169
 
169
170
  By default the `local` mode is active from `ruyi` 0.42.0 (inclusive) on, which
@@ -4,7 +4,7 @@ build-backend = "poetry.core.masonry.api"
4
4
 
5
5
  [project]
6
6
  name = "ruyi"
7
- version = "0.43.0-alpha.20251017"
7
+ version = "0.44.0"
8
8
  description = "Package manager for RuyiSDK"
9
9
  keywords = ["ruyi", "ruyisdk"]
10
10
  license = { file = "LICENSE-Apache.txt" }
@@ -22,6 +22,7 @@ classifiers = [
22
22
  "Programming Language :: Python :: 3.11",
23
23
  "Programming Language :: Python :: 3.12",
24
24
  "Programming Language :: Python :: 3.13",
25
+ "Programming Language :: Python :: 3.14",
25
26
  "Topic :: Software Development :: Build Tools",
26
27
  "Topic :: Software Development :: Embedded Systems",
27
28
  "Topic :: System :: Software Distribution",
@@ -33,7 +34,8 @@ dependencies = [
33
34
  "arpy",
34
35
  "fastjsonschema>=2.15.1",
35
36
  "jinja2 (>=3, <4)",
36
- "pygit2>=1.6",
37
+ "pygit2 (>=1.6, <1.19); python_version<'3.11'",
38
+ "pygit2>=1.6; python_version>='3.11'",
37
39
  "pyyaml>=5.4",
38
40
  "requests (>=2, <3)",
39
41
  "rich>=11.2.0",
@@ -39,11 +39,11 @@ def main(gm: GlobalModeProvider, gc: GlobalConfig, argv: list[str]) -> int:
39
39
  if not gm.is_cli_autocomplete:
40
40
  oobe = OOBE(gc)
41
41
 
42
- if tm := gc.telemetry:
43
- tm.check_first_run_status()
44
- tm.init_installation(False)
45
- atexit.register(tm.flush)
46
- oobe.handlers.append(tm.oobe_prompt)
42
+ tm = gc.telemetry
43
+ tm.check_first_run_status()
44
+ tm.init_installation(False)
45
+ atexit.register(tm.flush)
46
+ oobe.handlers.append(tm.oobe_prompt)
47
47
 
48
48
  oobe.maybe_prompt()
49
49
 
@@ -59,12 +59,11 @@ def main(gm: GlobalModeProvider, gc: GlobalConfig, argv: list[str]) -> int:
59
59
  from ..mux.runtime import mux_main
60
60
 
61
61
  # record an invocation and the command name being proxied to
62
- if tm := gc.telemetry:
63
- tm.record(
64
- TelemetryScope(None),
65
- "cli:mux-invocation-v1",
66
- target=os.path.basename(gm.argv0),
67
- )
62
+ gc.telemetry.record(
63
+ TelemetryScope(None),
64
+ "cli:mux-invocation-v1",
65
+ target=os.path.basename(gm.argv0),
66
+ )
68
67
 
69
68
  return mux_main(gm, gc, argv)
70
69
 
@@ -127,8 +126,16 @@ def main(gm: GlobalModeProvider, gc: GlobalConfig, argv: list[str]) -> int:
127
126
  except AttributeError:
128
127
  pass
129
128
 
130
- if tm := gc.telemetry:
131
- tm.print_telemetry_notice()
129
+ tm = gc.telemetry
130
+ tm.print_telemetry_notice()
131
+
132
+ # Do not record `ruyi telemetry --cron-upload` invocations.
133
+ skip_recording_invocation = telemetry_key == "telemetry" and getattr(
134
+ args,
135
+ "cron_upload",
136
+ False,
137
+ )
138
+ if not skip_recording_invocation:
132
139
  tm.record(
133
140
  TelemetryScope(None),
134
141
  "cli:invocation-v1",
@@ -30,13 +30,9 @@ class OOBE:
30
30
  ]
31
31
 
32
32
  def is_first_run(self) -> bool:
33
- if tm := self._gc.telemetry:
34
- return tm.is_first_run
35
- # cannot reliably determine first run status without telemetry
36
- # we may revisit this later if it turns out users want OOBE tips even
37
- # if they know how to disable telemetry (hence more likely to be power
38
- # users)
39
- return False
33
+ # We now always have our first-run indicator because of the minimal
34
+ # telemetry mode.
35
+ return self._gc.telemetry.is_first_run
40
36
 
41
37
  def should_prompt(self) -> bool:
42
38
  from ..utils.global_mode import is_env_var_truthy
@@ -241,8 +241,7 @@ def _do_reset(
241
241
 
242
242
  # do not record any telemetry data if we're purging it
243
243
  if all_state or telemetry:
244
- if tm := cfg.telemetry:
245
- tm.discard_events(True)
244
+ cfg.telemetry.discard_events(True)
246
245
 
247
246
  if all_state:
248
247
  status("removing state data")
@@ -297,17 +297,13 @@ class GlobalConfig:
297
297
  def telemetry_root(self) -> os.PathLike[Any]:
298
298
  return pathlib.Path(self.ensure_state_dir()) / "telemetry"
299
299
 
300
- @property
301
- def telemetry(self) -> "TelemetryProvider | None":
302
- return None if self.telemetry_mode == "off" else self._telemetry_provider
303
-
304
300
  @cached_property
305
- def _telemetry_provider(self) -> "TelemetryProvider | None":
306
- """Do not access directly; use the ``telemetry`` property instead."""
307
-
301
+ def telemetry(self) -> "TelemetryProvider":
308
302
  from ..telemetry.provider import TelemetryProvider
309
303
 
310
- return None if self.telemetry_mode == "off" else TelemetryProvider(self)
304
+ # for allowing minimal uploads when telemetry is off
305
+ minimal_mode = self.telemetry_mode == "off"
306
+ return TelemetryProvider(self, minimal_mode)
311
307
 
312
308
  @property
313
309
  def telemetry_mode(self) -> str:
@@ -9,14 +9,46 @@ from typing import Any, Final, Iterator, TypedDict
9
9
  from ...config import GlobalConfig
10
10
  from ...log import RuyiLogger, humanize_list
11
11
  from ...ruyipkg.atom import Atom
12
- from ...ruyipkg.pkg_manifest import EmulatorProgDecl
12
+ from ...ruyipkg.pkg_manifest import BoundPackageManifest, EmulatorProgDecl
13
13
  from ...ruyipkg.profile import ProfileProxy
14
14
  from ...utils.global_mode import ProvidesGlobalMode
15
15
  from ...utils.templating import render_template_str
16
- from . import ConfiguredTargetTuple
17
16
  from .emulator_cfg import ResolvedEmulatorProg
18
17
 
19
18
 
19
+ class ConfiguredTargetTuple(TypedDict):
20
+ target: str
21
+ toolchain_root: PathLike[Any]
22
+ toolchain_sysroot: PathLike[Any] | None
23
+ toolchain_flags: str
24
+ binutils_flavor: str
25
+ cc_flavor: str
26
+ gcc_install_dir: PathLike[Any] | None
27
+
28
+
29
+ class VenvPackageInfo(TypedDict):
30
+ repo_id: str
31
+ category: str
32
+ name: str
33
+ version: str
34
+
35
+
36
+ class VenvMetadata(TypedDict):
37
+ emulator_pkgs: dict[str, VenvPackageInfo]
38
+ extra_pkgs: list[VenvPackageInfo]
39
+ sysroot_pkg: VenvPackageInfo | None
40
+ toolchain_pkgs: dict[str, VenvPackageInfo]
41
+
42
+
43
+ def _venv_pkg_info_from_pkg(pkg: BoundPackageManifest) -> VenvPackageInfo:
44
+ return VenvPackageInfo(
45
+ repo_id=pkg.repo_id,
46
+ category=pkg.category,
47
+ name=pkg.name,
48
+ version=pkg.ver,
49
+ )
50
+
51
+
20
52
  def do_make_venv(
21
53
  config: GlobalConfig,
22
54
  host: str,
@@ -50,6 +82,12 @@ def do_make_venv(
50
82
  seen_target_tuples: set[str] = set()
51
83
  targets: list[ConfiguredTargetTuple] = []
52
84
  warn_differing_target_arch = False
85
+ venv_metadata = VenvMetadata(
86
+ emulator_pkgs={},
87
+ extra_pkgs=[],
88
+ sysroot_pkg=None,
89
+ toolchain_pkgs={},
90
+ )
53
91
 
54
92
  for tc_atom_str in tc_atoms_str:
55
93
  tc_atom = Atom.parse(tc_atom_str)
@@ -97,6 +135,7 @@ def do_make_venv(
97
135
  if with_sysroot:
98
136
  if tc_sysroot_relpath := tc_pm.toolchain_metadata.included_sysroot:
99
137
  tc_sysroot_dir = pathlib.Path(toolchain_root) / tc_sysroot_relpath
138
+ venv_metadata["sysroot_pkg"] = _venv_pkg_info_from_pkg(tc_pm)
100
139
  else:
101
140
  if sysroot_atom_str is None:
102
141
  logger.F(
@@ -156,6 +195,8 @@ def do_make_venv(
156
195
  )
157
196
  return 1
158
197
 
198
+ venv_metadata["sysroot_pkg"] = _venv_pkg_info_from_pkg(gcc_pkg_pm)
199
+
159
200
  # derive flags for (the quirks of) this toolchain
160
201
  tc_flags = profile.get_common_flags(tc_pm.toolchain_metadata.quirks)
161
202
 
@@ -177,6 +218,7 @@ def do_make_venv(
177
218
  logger.D(f"configuration for {target_tuple}: {configured_target}")
178
219
  targets.append(configured_target)
179
220
  seen_target_tuples.add(target_tuple)
221
+ venv_metadata["toolchain_pkgs"][target_tuple] = _venv_pkg_info_from_pkg(tc_pm)
180
222
 
181
223
  # record the target architecture for use in emulator package matching
182
224
  if not target_arch:
@@ -236,6 +278,8 @@ def do_make_venv(
236
278
  logger.F("cannot find the installed directory for the emulator")
237
279
  return 1
238
280
 
281
+ venv_metadata["emulator_pkgs"][target_arch] = _venv_pkg_info_from_pkg(emu_pm)
282
+
239
283
  # Now resolve extra commands to provide in the venv.
240
284
  extra_cmds: dict[str, str] = {}
241
285
  if extra_cmd_atoms_str:
@@ -276,6 +320,8 @@ def do_make_venv(
276
320
  return 1
277
321
  cmd_root = pathlib.Path(cmd_root)
278
322
 
323
+ venv_metadata["extra_pkgs"].append(_venv_pkg_info_from_pkg(extra_cmd_pm))
324
+
279
325
  for cmd, cmd_rel_path in extra_cmds_decl.items():
280
326
  # resolve the command path
281
327
  cmd_path = (cmd_root / cmd_rel_path).resolve()
@@ -305,6 +351,7 @@ def do_make_venv(
305
351
  emu_progs,
306
352
  emu_root,
307
353
  extra_cmds,
354
+ venv_metadata,
308
355
  override_name,
309
356
  )
310
357
  maker.provision()
@@ -350,6 +397,7 @@ class VenvMaker:
350
397
  emulator_progs: list[EmulatorProgDecl] | None,
351
398
  emulator_root: PathLike[Any] | None,
352
399
  extra_cmds: dict[str, str] | None,
400
+ metadata: VenvMetadata,
353
401
  override_name: str | None = None,
354
402
  ) -> None:
355
403
  self.gc = gc
@@ -359,6 +407,7 @@ class VenvMaker:
359
407
  self.emulator_progs = emulator_progs
360
408
  self.emulator_root = emulator_root
361
409
  self.extra_cmds = extra_cmds or {}
410
+ self.metadata = metadata
362
411
  self.override_name = override_name
363
412
 
364
413
  self.bindir = self.venv_root / "bin"
@@ -415,6 +464,7 @@ class VenvMaker:
415
464
  env_data = {
416
465
  "profile": self.profile.id,
417
466
  "sysroot": self.sysroot_destdir(None),
467
+ "metadata": self.metadata,
418
468
  }
419
469
  self.render_and_write(
420
470
  venv_root / "ruyi-venv.toml",
@@ -148,7 +148,7 @@ class UnsandboxedRuyiPluginLoader(BasePluginLoader[UnsandboxedModuleDict]):
148
148
  @staticmethod
149
149
  def source_to_code(
150
150
  data: "Buffer | str | ast.Module",
151
- path: "Buffer | str | os.PathLike[str]" = "<string>",
151
+ path: "str | os.PathLike[str]" = "<string>",
152
152
  ) -> CodeType:
153
153
  mod_ast: ast.Module
154
154
  if isinstance(data, ast.Module):
@@ -11,7 +11,7 @@ RESOURCES: Final = {
11
11
  "prompt.venv-created.txt.jinja": b"eNp1kTFvwkAMhff7FV7YStjbqWLqwMZSISSOO4dYJOfIvoRGiP9eXwR0KTedbOv5e8/bBmEkyYNvAZP9OHWYMpBC4gsEQZ8xVs598wCdn8CHTKPVgDIcJ1AeJFA6QTYh3/fCvVBp3+eIE2gQ6k0ylSG3Owli2h8p7VZ7iCQYMsv0Bj5FiPjUN3FKI5+L+EGGiZZ/zUPlroslUA06qTBnWNyc+4RaUJtHbdUL1vRTrPhWGYxtJDUgjHeW/5xX7mt270dPrT+25iTPszW3LV8KTe9z8+4c2LubuV6fILeb2ZrpMEUDLGDbFyHPWIE7VLhQbsDCjtOy8xFhvfFnhMzchsYbbU0tupLQBtUiDcKqc7GCdYPh/MoOzFA1iw2w4oezdaWujwiKhhpEymXNoP5kp02aZQjleFq5Xz21xdY=", # fmt: skip
12
12
  "ruyi-activate.bash.jinja": b"eNp9lN1u2kAQhe/3KSYGqiSVRUnuqIhEGqRESgLCBClKI2uxx/JKZh2t126o6yfqI/QuT9bxH2CHhBvEzpn1d2YO7sDCFxF4IkBYx5GGFUIcoQu/hPbBiMJYOQgrIfsq3giTO1okXKMBp54K17DikX/KOrAJY3C4lKEGFUsQGlyh0NHBhjEmPHgCo5tejq1r25o+zH9MzMyAEZ19M+D5O2gfJQP6oOOHYDzSZQVL9XSdE0aOEi96CD+79XHefPHlrGx8pUeenzNPMFaAulijwvEJpIWoAwoj1BAGLqBMhArlGqWGhCvBVwFGleqIcM3f0E2X4/lXO4Nn6tOxkhFoFSOQHSoAMbnoBFzRsLgGHgRFO1WrfnJszx8eb+zp7ZU9Gy+uh3QZ+YU9w/knL42MblNrbMv4+hIqXai2Z7HMfTQ7imLuvzQhZMID4eYDoKcV7bQhx8ei7tPewFRwdtF3MenLmOg/xbcGH8Bbgya7NXiPbg0+Jq9qNXhZL8rLyf3y0Jk9m0/vZosa94mAiXVQRUqG0sWIFpWvH1vEHbAw8KAWHLWwTA9a4anZMkYhL0VCKQww4Y3gtDPXpGBsCz9K050T+AO0hixj1aB2tllztzTiMhTVj62wT//MYVXbDwr7LAAHl5/28mHuhnw/vpuA2ctYe+4NB6WstpH2TMAgwsN9RveYXhco+Rphz4JxYpSN0iWA3vth1Psu3yNlMnfFqxtrfHk7qURmO6ONpBFCSl8kYtvsvv2d0+5g/8ryquztHzTke2mmRPwHax2J0Q==", # fmt: skip
13
13
  "ruyi-cache.toml.jinja": b"eNptUs1uhCAYvPsUX2nMtknjoccmve0e9tK9eDOGsIJK1r8CmhjjuxcUF6uexG+GmWHgFX5u4eULwpxLSHnBQH9LUpGMUbj3INqeB3C+GRpcztfwxfOihCQ5o7j7jL3BB57CLytbfOcV+ONz+Q1oGBwyjkhzWUU13R/tvkbUxhMbEqs6AzjxYINOZmkt4PEBHWjJDR5wxUr59q5VtPFDO9oMnTH3ZnezX+P/k6xFFREZU3Iltkq0gFY/9lRdF0lOeGXOSLlYHKPTFjnFUwo3TguSySP+BFj6XFMXIQfLXoq6VijW0XbTIz0LzYr7O9DiWZJgXklFigLrqJP0ZuaEN8Ch7LPobbtJSXHJFKFEEVyS5rjmHQvZwlHsUSZXpzR/S7PT3WDVNvoRuxpWU9epy/cHatoHPQ==", # fmt: skip
14
- "ruyi-venv.toml.jinja": b"eNqLTs7PS8tMj+UqKMpPy8xJVbBVUKquVoDxamuVuKpVFTLTFIori4vy80sUdFVruWBsiFoYD6JWVyE1LwWoHqgMAMZMHuE=", # fmt: skip
14
+ "ruyi-venv.toml.jinja": b"eNqtkOFqwyAQx7/7FBIIbWEN7AH2JEHCYUwqbTxRN1ZC3n0atQlpSxnbN/V+3v3uX3NUnewZ0QY7eRH0gxbjSPNtmgoyllR21F6tQXT0WE4knyObb5E9UqFaz3uM1INw0IIDRr6EsRKV//JOQscBuEGqz32Tmb0+zM2N0NjINovUu/SwY/MEDk70aK5LPb8kQMEglmK4pcKikGrpIZWTehQL9nHvrFcXac/GSxcsELf1Kg38DL2wVWIYCRPWyz1pc/Cjw6Als+1UMXxewKEJvI1zPdKhoQ5ML1wDhp/eqKZSPf9VSScGu48BP9DOeBWSWfUNwdzvolfWQaR8tcK3M3Dvv1VeU7PnI9EAsb8rOcQLP4FUv4t1++1Vrjf+X4L9AYyLQa0=", # fmt: skip
15
15
  "toolchain.cmake.jinja": b"eNqFkVFrwjAUhd/7Ky6IMGF274M9dG2cZWlT0joUhJDVaIuajKQTR+l/X6zOWccwb+F+5+Scmx5MjIBNuRaPTs/pQb7lawGu68Lc3g5nGPiR94pYRgj2x14Ys1GI0VNdw07IHdNKVdA0D5VSm7zgpXSPFnOn7g+hXIL5Mi3Tb64MwzjNPIxZQtEonB4Mf9CmOcmFXFiHs9LGchwjqrujQTpLMxSx2IsQ4FJ+7gd/hwklPkpTQsH6f2iVC2OUti9csj7zSZTYVi2V59fj6bQL7PctUfcv+w1tzF/NKIwDRgnJWOJlY+iUa5UX1YzgOi9gaXMVgi+ENsDlwn7Ku+a6FAZKCVUhoOJ6JSqr3JVaya2Q1X1XbfutNN+eBYUyHfzffCwiATrs6oV6EcToDdHBDRiHz9SjMyAxnt1iw9jHkwCd2G+4PsQk", # fmt: skip
16
16
  }
17
17
 
@@ -168,17 +168,16 @@ def do_install_atoms(
168
168
  for s in sv.render_known_issues(pm.repo.messages, config.lang_code):
169
169
  logger.I(s)
170
170
 
171
- if tm := config.telemetry:
172
- tm.record(
173
- TelemetryScope(mr.repo_id),
174
- "repo:package-install-v1",
175
- atom=a_str,
176
- host=canonicalized_host,
177
- pkg_category=pm.category,
178
- pkg_kinds=pm.kind,
179
- pkg_name=pm.name,
180
- pkg_version=pm.ver,
181
- )
171
+ config.telemetry.record(
172
+ TelemetryScope(mr.repo_id),
173
+ "repo:package-install-v1",
174
+ atom=a_str,
175
+ host=canonicalized_host,
176
+ pkg_category=pm.category,
177
+ pkg_kinds=pm.kind,
178
+ pkg_name=pm.name,
179
+ pkg_version=pm.ver,
180
+ )
182
181
 
183
182
  if pm.binary_metadata is not None:
184
183
  ret = _do_install_binary_pkg(
@@ -478,17 +477,16 @@ def do_uninstall_atoms(
478
477
  for a_str, pm in pms_to_uninstall:
479
478
  pkg_name = pm.name_for_installation
480
479
 
481
- if tm := config.telemetry:
482
- tm.record(
483
- TelemetryScope(mr.repo_id),
484
- "repo:package-uninstall-v1",
485
- atom=a_str,
486
- host=canonicalized_host,
487
- pkg_category=pm.category,
488
- pkg_kinds=pm.kind,
489
- pkg_name=pm.name,
490
- pkg_version=pm.ver,
491
- )
480
+ config.telemetry.record(
481
+ TelemetryScope(mr.repo_id),
482
+ "repo:package-uninstall-v1",
483
+ atom=a_str,
484
+ host=canonicalized_host,
485
+ pkg_category=pm.category,
486
+ pkg_kinds=pm.kind,
487
+ pkg_name=pm.name,
488
+ pkg_version=pm.ver,
489
+ )
492
490
 
493
491
  if pm.binary_metadata is not None:
494
492
  ret = _do_uninstall_binary_pkg(
@@ -18,8 +18,13 @@ class UploadPayload(TypedDict):
18
18
  fmt: int
19
19
  nonce: str
20
20
  ruyi_version: str
21
+ report_uuid: "NotRequired[str]"
22
+ """Optional field in case the client wishes to report this, and nothing
23
+ else. If `installation` is present, this field is ignored."""
21
24
  installation: "NotRequired[NodeInfo | None]"
25
+ """More detailed installation info that the client has user consent to report."""
22
26
  events: list[AggregatedTelemetryEvent]
27
+ """Aggregated telemetry events that the client has user consent to upload."""
23
28
 
24
29
 
25
30
  def stringify_param_val(v: object) -> str: