ruyi 0.44.0a20251118__py3-none-any.whl → 0.45.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.
- ruyi/__main__.py +16 -4
- ruyi/cli/cmd.py +6 -5
- ruyi/cli/config_cli.py +14 -11
- ruyi/cli/main.py +34 -17
- ruyi/cli/oobe.py +10 -10
- ruyi/cli/self_cli.py +49 -36
- ruyi/cli/user_input.py +42 -12
- ruyi/cli/version_cli.py +11 -5
- ruyi/config/__init__.py +30 -10
- ruyi/config/errors.py +19 -7
- ruyi/device/provision.py +116 -55
- ruyi/device/provision_cli.py +6 -3
- ruyi/i18n/__init__.py +129 -0
- ruyi/log/__init__.py +6 -5
- ruyi/mux/runtime.py +19 -6
- ruyi/mux/venv/maker.py +93 -35
- ruyi/mux/venv/venv_cli.py +13 -10
- ruyi/pluginhost/plugin_cli.py +4 -3
- ruyi/resource_bundle/__init__.py +22 -8
- ruyi/resource_bundle/__main__.py +6 -5
- ruyi/resource_bundle/data.py +13 -9
- ruyi/ruyipkg/admin_checksum.py +4 -1
- ruyi/ruyipkg/admin_cli.py +9 -6
- ruyi/ruyipkg/augmented_pkg.py +15 -14
- ruyi/ruyipkg/checksum.py +8 -2
- ruyi/ruyipkg/distfile.py +33 -9
- ruyi/ruyipkg/entity.py +12 -2
- ruyi/ruyipkg/entity_cli.py +20 -12
- ruyi/ruyipkg/entity_provider.py +11 -2
- ruyi/ruyipkg/fetcher.py +38 -9
- ruyi/ruyipkg/install.py +163 -64
- ruyi/ruyipkg/install_cli.py +18 -15
- ruyi/ruyipkg/list.py +27 -20
- ruyi/ruyipkg/list_cli.py +12 -7
- ruyi/ruyipkg/news.py +23 -11
- ruyi/ruyipkg/news_cli.py +10 -7
- ruyi/ruyipkg/profile_cli.py +8 -2
- ruyi/ruyipkg/repo.py +22 -8
- ruyi/ruyipkg/unpack.py +42 -8
- ruyi/ruyipkg/unpack_method.py +5 -1
- ruyi/ruyipkg/update_cli.py +8 -3
- ruyi/telemetry/aggregate.py +5 -0
- ruyi/telemetry/provider.py +292 -105
- ruyi/telemetry/store.py +68 -15
- ruyi/telemetry/telemetry_cli.py +32 -13
- ruyi/utils/git.py +18 -11
- ruyi/utils/prereqs.py +10 -5
- ruyi/utils/ssl_patch.py +2 -1
- ruyi/version.py +9 -3
- {ruyi-0.44.0a20251118.dist-info → ruyi-0.45.0.dist-info}/METADATA +4 -2
- ruyi-0.45.0.dist-info/RECORD +103 -0
- {ruyi-0.44.0a20251118.dist-info → ruyi-0.45.0.dist-info}/WHEEL +1 -1
- ruyi-0.44.0a20251118.dist-info/RECORD +0 -102
- {ruyi-0.44.0a20251118.dist-info → ruyi-0.45.0.dist-info}/entry_points.txt +0 -0
- {ruyi-0.44.0a20251118.dist-info → ruyi-0.45.0.dist-info}/licenses/LICENSE-Apache.txt +0 -0
ruyi/ruyipkg/fetcher.py
CHANGED
|
@@ -7,6 +7,7 @@ from typing import Any, Final
|
|
|
7
7
|
import requests
|
|
8
8
|
from rich import progress
|
|
9
9
|
|
|
10
|
+
from ..i18n import _
|
|
10
11
|
from ..log import RuyiLogger
|
|
11
12
|
|
|
12
13
|
ENV_OVERRIDE_FETCHER: Final = "RUYI_OVERRIDE_FETCHER"
|
|
@@ -40,19 +41,31 @@ class BaseFetcher:
|
|
|
40
41
|
) -> bool:
|
|
41
42
|
for t in range(retries):
|
|
42
43
|
if t > 0:
|
|
43
|
-
self._logger.I(
|
|
44
|
+
self._logger.I(
|
|
45
|
+
_("retrying download ({current} of {total} times)").format(
|
|
46
|
+
current=t + 1,
|
|
47
|
+
total=retries,
|
|
48
|
+
)
|
|
49
|
+
)
|
|
44
50
|
if self.fetch_one(url, dest, resume):
|
|
45
51
|
return True
|
|
46
52
|
return False
|
|
47
53
|
|
|
48
54
|
def fetch(self, *, resume: bool = False, retries: int = 3) -> None:
|
|
49
55
|
for url in self.urls:
|
|
50
|
-
self._logger.I(
|
|
56
|
+
self._logger.I(
|
|
57
|
+
_("downloading {url} to {dest}").format(
|
|
58
|
+
url=url,
|
|
59
|
+
dest=self.dest,
|
|
60
|
+
)
|
|
61
|
+
)
|
|
51
62
|
if self.fetch_one_with_retry(url, self.dest, resume, retries):
|
|
52
63
|
return
|
|
53
64
|
# all URLs have been tried and all have failed
|
|
54
65
|
raise RuntimeError(
|
|
55
|
-
|
|
66
|
+
_("failed to fetch '{dest}': all source URLs have failed").format(
|
|
67
|
+
dest=self.dest,
|
|
68
|
+
)
|
|
56
69
|
)
|
|
57
70
|
|
|
58
71
|
@classmethod
|
|
@@ -78,7 +91,7 @@ def get_usable_fetcher_cls(logger: RuyiLogger) -> type[BaseFetcher]:
|
|
|
78
91
|
|
|
79
92
|
if _fetcher_cache_populated:
|
|
80
93
|
if _cached_usable_fetcher_class is None:
|
|
81
|
-
raise RuntimeError("no fetcher is available on the system")
|
|
94
|
+
raise RuntimeError(_("no fetcher is available on the system"))
|
|
82
95
|
return _cached_usable_fetcher_class
|
|
83
96
|
|
|
84
97
|
_fetcher_cache_populated = True
|
|
@@ -88,10 +101,16 @@ def get_usable_fetcher_cls(logger: RuyiLogger) -> type[BaseFetcher]:
|
|
|
88
101
|
|
|
89
102
|
cls = KNOWN_FETCHERS.get(override_name)
|
|
90
103
|
if cls is None:
|
|
91
|
-
raise RuntimeError(
|
|
104
|
+
raise RuntimeError(
|
|
105
|
+
_("unknown fetcher '{name}'").format(
|
|
106
|
+
name=override_name,
|
|
107
|
+
)
|
|
108
|
+
)
|
|
92
109
|
if not cls.is_available(logger):
|
|
93
110
|
raise RuntimeError(
|
|
94
|
-
|
|
111
|
+
_("the requested fetcher '{name}' is unavailable on the system").format(
|
|
112
|
+
name=override_name,
|
|
113
|
+
)
|
|
95
114
|
)
|
|
96
115
|
_cached_usable_fetcher_class = cls
|
|
97
116
|
return cls
|
|
@@ -103,7 +122,7 @@ def get_usable_fetcher_cls(logger: RuyiLogger) -> type[BaseFetcher]:
|
|
|
103
122
|
_cached_usable_fetcher_class = cls
|
|
104
123
|
return cls
|
|
105
124
|
|
|
106
|
-
raise RuntimeError("no fetcher is available on the system")
|
|
125
|
+
raise RuntimeError(_("no fetcher is available on the system"))
|
|
107
126
|
|
|
108
127
|
|
|
109
128
|
class CurlFetcher(BaseFetcher):
|
|
@@ -152,7 +171,12 @@ class CurlFetcher(BaseFetcher):
|
|
|
152
171
|
retcode = subprocess.call(argv)
|
|
153
172
|
if retcode != 0:
|
|
154
173
|
self._logger.W(
|
|
155
|
-
|
|
174
|
+
_(
|
|
175
|
+
"failed to fetch distfile: command '{cmd}' returned {retcode}"
|
|
176
|
+
).format(
|
|
177
|
+
cmd=" ".join(argv),
|
|
178
|
+
retcode=retcode,
|
|
179
|
+
)
|
|
156
180
|
)
|
|
157
181
|
return False
|
|
158
182
|
|
|
@@ -190,7 +214,12 @@ class WgetFetcher(BaseFetcher):
|
|
|
190
214
|
retcode = subprocess.call(argv)
|
|
191
215
|
if retcode != 0:
|
|
192
216
|
self._logger.W(
|
|
193
|
-
|
|
217
|
+
_(
|
|
218
|
+
"failed to fetch distfile: command '{cmd}' returned {retcode}"
|
|
219
|
+
).format(
|
|
220
|
+
cmd=" ".join(argv),
|
|
221
|
+
retcode=retcode,
|
|
222
|
+
)
|
|
194
223
|
)
|
|
195
224
|
return False
|
|
196
225
|
|
ruyi/ruyipkg/install.py
CHANGED
|
@@ -8,6 +8,7 @@ from ruyi.ruyipkg.state import BoundInstallationStateStore
|
|
|
8
8
|
|
|
9
9
|
from ..cli.user_input import ask_for_yesno_confirmation
|
|
10
10
|
from ..config import GlobalConfig
|
|
11
|
+
from ..i18n import _
|
|
11
12
|
from ..telemetry.scope import TelemetryScope
|
|
12
13
|
from .atom import Atom
|
|
13
14
|
from .distfile import Distfile
|
|
@@ -43,12 +44,16 @@ def do_extract_atoms(
|
|
|
43
44
|
a = Atom.parse(a_str)
|
|
44
45
|
pm = a.match_in_repo(mr, cfg.include_prereleases)
|
|
45
46
|
if pm is None:
|
|
46
|
-
logger.F(
|
|
47
|
+
logger.F(
|
|
48
|
+
_("atom {atom} matches no package in the repository").format(
|
|
49
|
+
atom=a_str,
|
|
50
|
+
)
|
|
51
|
+
)
|
|
47
52
|
return 1
|
|
48
53
|
|
|
49
54
|
sv = pm.service_level
|
|
50
55
|
if sv.has_known_issues:
|
|
51
|
-
logger.W("package has known issue(s)")
|
|
56
|
+
logger.W(_("package has known issue(s)"))
|
|
52
57
|
for s in sv.render_known_issues(pm.repo.messages, cfg.lang_code):
|
|
53
58
|
logger.I(s)
|
|
54
59
|
|
|
@@ -97,12 +102,20 @@ def _do_extract_pkg(
|
|
|
97
102
|
bm = pm.binary_metadata
|
|
98
103
|
sm = pm.source_metadata
|
|
99
104
|
if bm is None and sm is None:
|
|
100
|
-
logger.F(
|
|
105
|
+
logger.F(
|
|
106
|
+
_("don't know how to extract package [green]{pkg}[/]").format(
|
|
107
|
+
pkg=pkg_name,
|
|
108
|
+
)
|
|
109
|
+
)
|
|
101
110
|
return 2
|
|
102
111
|
|
|
103
112
|
if bm is not None and sm is not None:
|
|
104
113
|
logger.F(
|
|
105
|
-
|
|
114
|
+
_(
|
|
115
|
+
"cannot handle package [green]{pkg}[/]: package is both binary and source"
|
|
116
|
+
).format(
|
|
117
|
+
pkg=pkg_name,
|
|
118
|
+
)
|
|
106
119
|
)
|
|
107
120
|
return 2
|
|
108
121
|
|
|
@@ -114,7 +127,10 @@ def _do_extract_pkg(
|
|
|
114
127
|
|
|
115
128
|
if not distfiles_for_host:
|
|
116
129
|
logger.F(
|
|
117
|
-
|
|
130
|
+
_("package [green]{pkg}[/] declares no distfile for host {host}").format(
|
|
131
|
+
pkg=pkg_name,
|
|
132
|
+
host=canonicalized_host,
|
|
133
|
+
)
|
|
118
134
|
)
|
|
119
135
|
return 2
|
|
120
136
|
|
|
@@ -130,13 +146,21 @@ def _do_extract_pkg(
|
|
|
130
146
|
logger.D("skipping extraction because [yellow]--fetch-only[/] is given")
|
|
131
147
|
continue
|
|
132
148
|
|
|
133
|
-
logger.I(
|
|
149
|
+
logger.I(
|
|
150
|
+
_("extracting [green]{distfile}[/] for package [green]{pkg}[/]").format(
|
|
151
|
+
distfile=df_name,
|
|
152
|
+
pkg=pkg_name,
|
|
153
|
+
)
|
|
154
|
+
)
|
|
134
155
|
# unpack into destination
|
|
135
156
|
df.unpack(dest_dir, logger)
|
|
136
157
|
|
|
137
158
|
if not fetch_only:
|
|
138
159
|
logger.I(
|
|
139
|
-
|
|
160
|
+
_("package [green]{pkg}[/] has been extracted to {dest_dir}").format(
|
|
161
|
+
pkg=pkg_name,
|
|
162
|
+
dest_dir=dest_dir,
|
|
163
|
+
)
|
|
140
164
|
)
|
|
141
165
|
|
|
142
166
|
return 0
|
|
@@ -158,27 +182,28 @@ def do_install_atoms(
|
|
|
158
182
|
a = Atom.parse(a_str)
|
|
159
183
|
pm = a.match_in_repo(mr, config.include_prereleases)
|
|
160
184
|
if pm is None:
|
|
161
|
-
logger.F(
|
|
185
|
+
logger.F(
|
|
186
|
+
_("atom {atom} matches no package in the repository").format(atom=a_str)
|
|
187
|
+
)
|
|
162
188
|
return 1
|
|
163
189
|
pkg_name = pm.name_for_installation
|
|
164
190
|
|
|
165
191
|
sv = pm.service_level
|
|
166
192
|
if sv.has_known_issues:
|
|
167
|
-
logger.W("package has known issue(s)")
|
|
193
|
+
logger.W(_("package has known issue(s)"))
|
|
168
194
|
for s in sv.render_known_issues(pm.repo.messages, config.lang_code):
|
|
169
195
|
logger.I(s)
|
|
170
196
|
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
)
|
|
197
|
+
config.telemetry.record(
|
|
198
|
+
TelemetryScope(mr.repo_id),
|
|
199
|
+
"repo:package-install-v1",
|
|
200
|
+
atom=a_str,
|
|
201
|
+
host=canonicalized_host,
|
|
202
|
+
pkg_category=pm.category,
|
|
203
|
+
pkg_kinds=pm.kind,
|
|
204
|
+
pkg_name=pm.name,
|
|
205
|
+
pkg_version=pm.ver,
|
|
206
|
+
)
|
|
182
207
|
|
|
183
208
|
if pm.binary_metadata is not None:
|
|
184
209
|
ret = _do_install_binary_pkg(
|
|
@@ -214,7 +239,11 @@ def do_install_atoms(
|
|
|
214
239
|
return ret
|
|
215
240
|
continue
|
|
216
241
|
|
|
217
|
-
logger.F(
|
|
242
|
+
logger.F(
|
|
243
|
+
_("don't know how to handle non-binary package [green]{pkg}[/]").format(
|
|
244
|
+
pkg=pkg_name,
|
|
245
|
+
)
|
|
246
|
+
)
|
|
218
247
|
return 2
|
|
219
248
|
|
|
220
249
|
return 0
|
|
@@ -250,11 +279,17 @@ def _do_install_binary_pkg(
|
|
|
250
279
|
|
|
251
280
|
if is_installed:
|
|
252
281
|
if not reinstall:
|
|
253
|
-
logger.I(
|
|
282
|
+
logger.I(
|
|
283
|
+
_("skipping already installed package [green]{pkg}[/]").format(
|
|
284
|
+
pkg=pkg_name,
|
|
285
|
+
)
|
|
286
|
+
)
|
|
254
287
|
return 0
|
|
255
288
|
|
|
256
289
|
logger.W(
|
|
257
|
-
|
|
290
|
+
_(
|
|
291
|
+
"package [green]{pkg}[/] seems already installed; purging and re-installing due to [yellow]--reinstall[/]"
|
|
292
|
+
).format(pkg=pkg_name)
|
|
258
293
|
)
|
|
259
294
|
# Remove from state tracking before purging
|
|
260
295
|
rgs.remove_installation(
|
|
@@ -291,7 +326,12 @@ def _do_install_binary_pkg(
|
|
|
291
326
|
install_path=install_root,
|
|
292
327
|
)
|
|
293
328
|
|
|
294
|
-
logger.I(
|
|
329
|
+
logger.I(
|
|
330
|
+
_("package [green]{pkg}[/] installed to [yellow]{install_root}[/]").format(
|
|
331
|
+
pkg=pkg_name,
|
|
332
|
+
install_root=install_root,
|
|
333
|
+
)
|
|
334
|
+
)
|
|
295
335
|
return 0
|
|
296
336
|
|
|
297
337
|
|
|
@@ -313,7 +353,10 @@ def _do_install_binary_pkg_to(
|
|
|
313
353
|
distfiles_for_host = bm.get_distfile_names_for_host(str(canonicalized_host))
|
|
314
354
|
if not distfiles_for_host:
|
|
315
355
|
logger.F(
|
|
316
|
-
|
|
356
|
+
_("package [green]{pkg}[/] declares no binary for host {host}").format(
|
|
357
|
+
pkg=pkg_name,
|
|
358
|
+
host=canonicalized_host,
|
|
359
|
+
)
|
|
317
360
|
)
|
|
318
361
|
return 2
|
|
319
362
|
|
|
@@ -324,10 +367,17 @@ def _do_install_binary_pkg_to(
|
|
|
324
367
|
df.ensure(logger)
|
|
325
368
|
|
|
326
369
|
if fetch_only:
|
|
327
|
-
logger.D(
|
|
370
|
+
logger.D(
|
|
371
|
+
_("skipping installation because [yellow]--fetch-only[/] is given")
|
|
372
|
+
)
|
|
328
373
|
continue
|
|
329
374
|
|
|
330
|
-
logger.I(
|
|
375
|
+
logger.I(
|
|
376
|
+
_("extracting [green]{distfile}[/] for package [green]{pkg}[/]").format(
|
|
377
|
+
distfile=df_name,
|
|
378
|
+
pkg=pkg_name,
|
|
379
|
+
)
|
|
380
|
+
)
|
|
331
381
|
df.unpack(install_root, logger)
|
|
332
382
|
|
|
333
383
|
return 0
|
|
@@ -362,11 +412,17 @@ def _do_install_blob_pkg(
|
|
|
362
412
|
|
|
363
413
|
if is_installed:
|
|
364
414
|
if not reinstall:
|
|
365
|
-
logger.I(
|
|
415
|
+
logger.I(
|
|
416
|
+
_("skipping already installed package [green]{pkg}[/]").format(
|
|
417
|
+
pkg=pkg_name,
|
|
418
|
+
)
|
|
419
|
+
)
|
|
366
420
|
return 0
|
|
367
421
|
|
|
368
422
|
logger.W(
|
|
369
|
-
|
|
423
|
+
_(
|
|
424
|
+
"package [green]{pkg}[/] seems already installed; purging and re-installing due to [yellow]--reinstall[/]"
|
|
425
|
+
).format(pkg=pkg_name)
|
|
370
426
|
)
|
|
371
427
|
# Remove from state tracking before purging
|
|
372
428
|
rgs.remove_installation(
|
|
@@ -402,7 +458,12 @@ def _do_install_blob_pkg(
|
|
|
402
458
|
install_path=install_root,
|
|
403
459
|
)
|
|
404
460
|
|
|
405
|
-
logger.I(
|
|
461
|
+
logger.I(
|
|
462
|
+
_("package [green]{pkg}[/] installed to [yellow]{install_root}[/]").format(
|
|
463
|
+
pkg=pkg_name,
|
|
464
|
+
install_root=install_root,
|
|
465
|
+
)
|
|
466
|
+
)
|
|
406
467
|
return 0
|
|
407
468
|
|
|
408
469
|
|
|
@@ -421,7 +482,9 @@ def _do_install_blob_pkg_to(
|
|
|
421
482
|
dfs = pm.distfiles
|
|
422
483
|
distfile_names = bm.get_distfile_names()
|
|
423
484
|
if not distfile_names:
|
|
424
|
-
logger.F(
|
|
485
|
+
logger.F(
|
|
486
|
+
_("package [green]{pkg}[/] declares no blob distfile").format(pkg=pkg_name)
|
|
487
|
+
)
|
|
425
488
|
return 2
|
|
426
489
|
|
|
427
490
|
for df_name in distfile_names:
|
|
@@ -431,10 +494,17 @@ def _do_install_blob_pkg_to(
|
|
|
431
494
|
df.ensure(logger)
|
|
432
495
|
|
|
433
496
|
if fetch_only:
|
|
434
|
-
logger.D(
|
|
497
|
+
logger.D(
|
|
498
|
+
_("skipping installation because [yellow]--fetch-only[/] is given")
|
|
499
|
+
)
|
|
435
500
|
continue
|
|
436
501
|
|
|
437
|
-
logger.I(
|
|
502
|
+
logger.I(
|
|
503
|
+
_("extracting [green]{distfile}[/] for package [green]{pkg}[/]").format(
|
|
504
|
+
distfile=df_name,
|
|
505
|
+
pkg=pkg_name,
|
|
506
|
+
)
|
|
507
|
+
)
|
|
438
508
|
df.unpack_or_symlink(install_root, logger)
|
|
439
509
|
|
|
440
510
|
return 0
|
|
@@ -458,37 +528,46 @@ def do_uninstall_atoms(
|
|
|
458
528
|
a = Atom.parse(a_str)
|
|
459
529
|
pm = a.match_in_repo(bis, config.include_prereleases)
|
|
460
530
|
if pm is None:
|
|
461
|
-
logger.F(
|
|
531
|
+
logger.F(
|
|
532
|
+
_("atom [yellow]{atom}[/] is non-existent or not installed").format(
|
|
533
|
+
atom=a_str,
|
|
534
|
+
)
|
|
535
|
+
)
|
|
462
536
|
return 1
|
|
463
537
|
pms_to_uninstall.append((a_str, pm))
|
|
464
538
|
|
|
465
539
|
if not pms_to_uninstall:
|
|
466
|
-
logger.I("no packages to uninstall")
|
|
540
|
+
logger.I(_("no packages to uninstall"))
|
|
467
541
|
return 0
|
|
468
542
|
|
|
469
|
-
logger.I("the following packages will be uninstalled:")
|
|
470
|
-
for
|
|
471
|
-
logger.I(
|
|
543
|
+
logger.I(_("the following packages will be uninstalled:"))
|
|
544
|
+
for _unused, pm in pms_to_uninstall:
|
|
545
|
+
logger.I(
|
|
546
|
+
_(" - [green]{category}/{name}[/] ({version})").format(
|
|
547
|
+
category=pm.category,
|
|
548
|
+
name=pm.name,
|
|
549
|
+
version=pm.ver,
|
|
550
|
+
)
|
|
551
|
+
)
|
|
472
552
|
|
|
473
553
|
if not assume_yes:
|
|
474
|
-
if not ask_for_yesno_confirmation(logger, "Proceed?", default=False):
|
|
475
|
-
logger.I("uninstallation aborted")
|
|
554
|
+
if not ask_for_yesno_confirmation(logger, _("Proceed?"), default=False):
|
|
555
|
+
logger.I(_("uninstallation aborted"))
|
|
476
556
|
return 0
|
|
477
557
|
|
|
478
558
|
for a_str, pm in pms_to_uninstall:
|
|
479
559
|
pkg_name = pm.name_for_installation
|
|
480
560
|
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
)
|
|
561
|
+
config.telemetry.record(
|
|
562
|
+
TelemetryScope(mr.repo_id),
|
|
563
|
+
"repo:package-uninstall-v1",
|
|
564
|
+
atom=a_str,
|
|
565
|
+
host=canonicalized_host,
|
|
566
|
+
pkg_category=pm.category,
|
|
567
|
+
pkg_kinds=pm.kind,
|
|
568
|
+
pkg_name=pm.name,
|
|
569
|
+
pkg_version=pm.ver,
|
|
570
|
+
)
|
|
492
571
|
|
|
493
572
|
if pm.binary_metadata is not None:
|
|
494
573
|
ret = _do_uninstall_binary_pkg(
|
|
@@ -506,7 +585,11 @@ def do_uninstall_atoms(
|
|
|
506
585
|
return ret
|
|
507
586
|
continue
|
|
508
587
|
|
|
509
|
-
logger.F(
|
|
588
|
+
logger.F(
|
|
589
|
+
_("don't know how to handle non-binary package [green]{pkg}[/]").format(
|
|
590
|
+
pkg=pkg_name,
|
|
591
|
+
)
|
|
592
|
+
)
|
|
510
593
|
return 2
|
|
511
594
|
|
|
512
595
|
return 0
|
|
@@ -536,21 +619,29 @@ def _do_uninstall_binary_pkg(
|
|
|
536
619
|
# Check directory existence if the PM state says the package is not installed
|
|
537
620
|
if not is_installed:
|
|
538
621
|
if not os.path.exists(install_root):
|
|
539
|
-
logger.I(
|
|
622
|
+
logger.I(
|
|
623
|
+
_("skipping not-installed package [green]{pkg}[/]").format(
|
|
624
|
+
pkg=pkg_name,
|
|
625
|
+
)
|
|
626
|
+
)
|
|
540
627
|
return 0
|
|
541
628
|
|
|
542
629
|
# There may be potentially user-generated data in the directory,
|
|
543
630
|
# let's be safe and fail the process.
|
|
544
631
|
logger.F(
|
|
545
|
-
|
|
632
|
+
_(
|
|
633
|
+
"package [green]{pkg}[/] is not tracked as installed, but its directory [yellow]{install_root}[/] exists."
|
|
634
|
+
).format(pkg=pkg_name, install_root=install_root)
|
|
546
635
|
)
|
|
547
|
-
logger.I("Please remove it manually if you are sure it's safe to do so.")
|
|
636
|
+
logger.I(_("Please remove it manually if you are sure it's safe to do so."))
|
|
548
637
|
logger.I(
|
|
549
|
-
|
|
638
|
+
_(
|
|
639
|
+
"If you believe this is a bug, please file an issue at [yellow]https://github.com/ruyisdk/ruyi/issues[/]."
|
|
640
|
+
)
|
|
550
641
|
)
|
|
551
642
|
return 1
|
|
552
643
|
|
|
553
|
-
logger.I(
|
|
644
|
+
logger.I(_("uninstalling package [green]{pkg}[/]").format(pkg=pkg_name))
|
|
554
645
|
if is_installed:
|
|
555
646
|
rgs.remove_installation(
|
|
556
647
|
pm.repo_id,
|
|
@@ -563,7 +654,7 @@ def _do_uninstall_binary_pkg(
|
|
|
563
654
|
if os.path.exists(install_root):
|
|
564
655
|
shutil.rmtree(install_root)
|
|
565
656
|
|
|
566
|
-
logger.I(
|
|
657
|
+
logger.I(_("package [green]{pkg}[/] uninstalled").format(pkg=pkg_name))
|
|
567
658
|
return 0
|
|
568
659
|
|
|
569
660
|
|
|
@@ -590,21 +681,29 @@ def _do_uninstall_blob_pkg(
|
|
|
590
681
|
# Check directory existence if the PM state says the package is not installed
|
|
591
682
|
if not is_installed:
|
|
592
683
|
if not os.path.exists(install_root):
|
|
593
|
-
logger.I(
|
|
684
|
+
logger.I(
|
|
685
|
+
_("skipping not-installed package [green]{pkg}[/]").format(
|
|
686
|
+
pkg=pkg_name,
|
|
687
|
+
)
|
|
688
|
+
)
|
|
594
689
|
return 0
|
|
595
690
|
|
|
596
691
|
# There may be potentially user-generated data in the directory,
|
|
597
692
|
# let's be safe and fail the process.
|
|
598
693
|
logger.F(
|
|
599
|
-
|
|
694
|
+
_(
|
|
695
|
+
"package [green]{pkg}[/] is not tracked as installed, but its directory [yellow]{install_root}[/] exists."
|
|
696
|
+
).format(pkg=pkg_name, install_root=install_root)
|
|
600
697
|
)
|
|
601
|
-
logger.I("Please remove it manually if you are sure it's safe to do so.")
|
|
698
|
+
logger.I(_("Please remove it manually if you are sure it's safe to do so."))
|
|
602
699
|
logger.I(
|
|
603
|
-
|
|
700
|
+
_(
|
|
701
|
+
"If you believe this is a bug, please file an issue at [yellow]https://github.com/ruyisdk/ruyi/issues[/]."
|
|
702
|
+
)
|
|
604
703
|
)
|
|
605
704
|
return 1
|
|
606
705
|
|
|
607
|
-
logger.I(
|
|
706
|
+
logger.I(_("uninstalling package [green]{pkg}[/]").format(pkg=pkg_name))
|
|
608
707
|
if is_installed:
|
|
609
708
|
rgs.remove_installation(
|
|
610
709
|
pm.repo_id,
|
|
@@ -617,5 +716,5 @@ def _do_uninstall_blob_pkg(
|
|
|
617
716
|
if os.path.exists(install_root):
|
|
618
717
|
shutil.rmtree(install_root)
|
|
619
718
|
|
|
620
|
-
logger.I(
|
|
719
|
+
logger.I(_("package [green]{pkg}[/] uninstalled").format(pkg=pkg_name))
|
|
621
720
|
return 0
|
ruyi/ruyipkg/install_cli.py
CHANGED
|
@@ -3,6 +3,7 @@ import pathlib
|
|
|
3
3
|
from typing import TYPE_CHECKING
|
|
4
4
|
|
|
5
5
|
from ..cli.cmd import RootCommand
|
|
6
|
+
from ..i18n import _
|
|
6
7
|
from .cli_completion import package_completer_builder
|
|
7
8
|
from .host import get_native_host
|
|
8
9
|
|
|
@@ -14,7 +15,7 @@ if TYPE_CHECKING:
|
|
|
14
15
|
class ExtractCommand(
|
|
15
16
|
RootCommand,
|
|
16
17
|
cmd="extract",
|
|
17
|
-
help="Fetch package(s) then extract to current directory",
|
|
18
|
+
help=_("Fetch package(s) then extract to current directory"),
|
|
18
19
|
):
|
|
19
20
|
@classmethod
|
|
20
21
|
def configure_args(cls, gc: "GlobalConfig", p: "ArgumentParser") -> None:
|
|
@@ -22,7 +23,7 @@ class ExtractCommand(
|
|
|
22
23
|
"atom",
|
|
23
24
|
type=str,
|
|
24
25
|
nargs="+",
|
|
25
|
-
help="Specifier (atom) of the package(s) to extract",
|
|
26
|
+
help=_("Specifier (atom) of the package(s) to extract"),
|
|
26
27
|
)
|
|
27
28
|
if gc.is_cli_autocomplete:
|
|
28
29
|
a.completer = package_completer_builder(gc)
|
|
@@ -33,24 +34,26 @@ class ExtractCommand(
|
|
|
33
34
|
type=str,
|
|
34
35
|
metavar="DESTDIR",
|
|
35
36
|
default=".",
|
|
36
|
-
help="Destination directory to extract to (default: current directory)",
|
|
37
|
+
help=_("Destination directory to extract to (default: current directory)"),
|
|
37
38
|
)
|
|
38
39
|
p.add_argument(
|
|
39
40
|
"--extract-without-subdir",
|
|
40
41
|
action="store_true",
|
|
41
|
-
help=
|
|
42
|
+
help=_(
|
|
43
|
+
"Extract files directly into DESTDIR instead of package-named subdirectories"
|
|
44
|
+
),
|
|
42
45
|
)
|
|
43
46
|
p.add_argument(
|
|
44
47
|
"-f",
|
|
45
48
|
"--fetch-only",
|
|
46
49
|
action="store_true",
|
|
47
|
-
help="Fetch distribution files only without installing",
|
|
50
|
+
help=_("Fetch distribution files only without installing"),
|
|
48
51
|
)
|
|
49
52
|
p.add_argument(
|
|
50
53
|
"--host",
|
|
51
54
|
type=str,
|
|
52
55
|
default=get_native_host(),
|
|
53
|
-
help="Override the host architecture (normally not needed)",
|
|
56
|
+
help=_("Override the host architecture (normally not needed)"),
|
|
54
57
|
)
|
|
55
58
|
|
|
56
59
|
@classmethod
|
|
@@ -81,7 +84,7 @@ class InstallCommand(
|
|
|
81
84
|
RootCommand,
|
|
82
85
|
cmd="install",
|
|
83
86
|
aliases=["i"],
|
|
84
|
-
help="Install package from configured repository",
|
|
87
|
+
help=_("Install package from configured repository"),
|
|
85
88
|
):
|
|
86
89
|
@classmethod
|
|
87
90
|
def configure_args(cls, gc: "GlobalConfig", p: "ArgumentParser") -> None:
|
|
@@ -89,7 +92,7 @@ class InstallCommand(
|
|
|
89
92
|
"atom",
|
|
90
93
|
type=str,
|
|
91
94
|
nargs="+",
|
|
92
|
-
help="Specifier (atom) of the package to install",
|
|
95
|
+
help=_("Specifier (atom) of the package to install"),
|
|
93
96
|
)
|
|
94
97
|
if gc.is_cli_autocomplete:
|
|
95
98
|
a.completer = package_completer_builder(gc)
|
|
@@ -98,18 +101,18 @@ class InstallCommand(
|
|
|
98
101
|
"-f",
|
|
99
102
|
"--fetch-only",
|
|
100
103
|
action="store_true",
|
|
101
|
-
help="Fetch distribution files only without installing",
|
|
104
|
+
help=_("Fetch distribution files only without installing"),
|
|
102
105
|
)
|
|
103
106
|
p.add_argument(
|
|
104
107
|
"--host",
|
|
105
108
|
type=str,
|
|
106
109
|
default=get_native_host(),
|
|
107
|
-
help="Override the host architecture (normally not needed)",
|
|
110
|
+
help=_("Override the host architecture (normally not needed)"),
|
|
108
111
|
)
|
|
109
112
|
p.add_argument(
|
|
110
113
|
"--reinstall",
|
|
111
114
|
action="store_true",
|
|
112
|
-
help="Force re-installation of already installed packages",
|
|
115
|
+
help=_("Force re-installation of already installed packages"),
|
|
113
116
|
)
|
|
114
117
|
|
|
115
118
|
@classmethod
|
|
@@ -136,7 +139,7 @@ class UninstallCommand(
|
|
|
136
139
|
RootCommand,
|
|
137
140
|
cmd="uninstall",
|
|
138
141
|
aliases=["remove", "rm"],
|
|
139
|
-
help="Uninstall installed packages",
|
|
142
|
+
help=_("Uninstall installed packages"),
|
|
140
143
|
):
|
|
141
144
|
@classmethod
|
|
142
145
|
def configure_args(cls, gc: "GlobalConfig", p: argparse.ArgumentParser) -> None:
|
|
@@ -144,20 +147,20 @@ class UninstallCommand(
|
|
|
144
147
|
"atom",
|
|
145
148
|
type=str,
|
|
146
149
|
nargs="+",
|
|
147
|
-
help="Specifier (atom) of the package to uninstall",
|
|
150
|
+
help=_("Specifier (atom) of the package to uninstall"),
|
|
148
151
|
)
|
|
149
152
|
p.add_argument(
|
|
150
153
|
"--host",
|
|
151
154
|
type=str,
|
|
152
155
|
default=get_native_host(),
|
|
153
|
-
help="Override the host architecture (normally not needed)",
|
|
156
|
+
help=_("Override the host architecture (normally not needed)"),
|
|
154
157
|
)
|
|
155
158
|
p.add_argument(
|
|
156
159
|
"-y",
|
|
157
160
|
"--yes",
|
|
158
161
|
action="store_true",
|
|
159
162
|
dest="assume_yes",
|
|
160
|
-
help="Assume yes to all prompts",
|
|
163
|
+
help=_("Assume yes to all prompts"),
|
|
161
164
|
)
|
|
162
165
|
|
|
163
166
|
@classmethod
|