Compare commits

...

19 Commits

Author SHA1 Message Date
SteveLauC
4df30c2587 chore: release v16.0.2 (#995) 2024-12-07 15:21:19 +08:00
Andre Toerien
305a5fbcae fix(poetry): skip if not installed with official script (#989)
* fix(poetry): skip if not installed with official script

* feat(poetry): add poetry_force_self_update config option

* docs: give this config a more detailed explanation

---------

Co-authored-by: Steve Lau <stevelauc@outlook.com>
2024-12-07 15:09:52 +08:00
Tulip Blossom
4f4dcbb643 feat: add bootc support to Fedora atomic distros
* feat(bootc): add Bootc support + docs

Co-authored-by: Steve Lau <stevelauc@outlook.com>

* docs(bootc): specify that itll supercede rpm-ostree if enabled :p

---------

Co-authored-by: Steve Lau <stevelauc@outlook.com>
2024-11-19 11:07:12 +08:00
Laura Demkowicz-Duffy
202897ba35 refactor: disable julia startup file for julia package update (#983)
* refactor(julia): disable julia startup file for julia package update

* feat(julia): add configuration option for julia startup file

* fix: deny unknown fields on JuliaConfig deserialisation

Co-authored-by: SteveLauC <stevelauc@outlook.com>

* doc(julia): clarify startup_file option purpose

---------

Co-authored-by: SteveLauC <stevelauc@outlook.com>
2024-11-19 09:17:51 +08:00
Youn Mélois
444689c899 feat: allow version specification for deno (#970)
* feat: allow version specification for deno

* fix: missing quotes for string in toml file

Co-authored-by: SteveLauC <stevelauc@outlook.com>

* fix: deno upgrade for different executable versions

* fix: tell apart the two cases for v1.x in SkipStep reason

* docs: add comments and documentation on version method for deno

* chore: add explanatory comment on stable channel that does nothing

Co-authored-by: SteveLauC <stevelauc@outlook.com>

---------

Co-authored-by: SteveLauC <stevelauc@outlook.com>
2024-10-29 18:09:47 +08:00
Gudsfile
98ec13f8db i18n(app.yml): new language fr (#969)
Apply suggestions from code review

Co-authored-by: SteveLauC <stevelauc@outlook.com>
2024-10-29 16:34:44 +08:00
Lucas Parzianello
39f76a3a71 uv step: checking self subcommand exits; fixes #942 (#971)
* uv step: checking self subcommand exits; fixes #942

* uv: fixing return behavior

---------

Co-authored-by: Lucas Parzianello <lucaspar@users.noreply.github.com>
2024-10-29 15:40:31 +08:00
Ricardo Torres
f181a795a6 refactor: flip order of mise upgrade and mise plugins update (#968)
flip order of mise plugins update and mise upgrade to attempt updating plugins first.
2024-10-28 09:59:22 +08:00
Andreas02-dev
ea2f3e07e9 feat(microsoft_store): Add Microsoft Store step for Windows (#963)
* feat(microsoft_store): Add Microsoft Store step for Windows

Add Microsoft Store Apps update step for Windows as Winget cannot update all Microsoft Store apps yet.

Closes #912

* style(translation): modify `zh_TW` translation
2024-10-23 08:15:46 +08:00
SteveLauC
8aad6eae0d refactor: add missing i18n for OpenBSD steps (#965) 2024-10-22 08:47:15 +08:00
SteveLauC
e86e5fe3e7 docs: document that we need to translate user-facing texts (#966) 2024-10-22 08:46:59 +08:00
λP.(P izzy)
2c2569c4f8 Improve OpenBSD -CURRENT detection and Dry-run feedback (#954)
* Improve OpenBSD -CURRENT detection and Dry-run feedback

This commit improves the -CURRENT detection by way of parsing `/etc/motd`. This change is more future-proof as when OpenBSD nears a stable release, `uname` will temporarily report like -STABLE.

This commit *also* adds feedback if -CURRENT is found to make debugging this feature easier with `--dry-run`, or, just a regular run as well.

* Make OpenBSD step less talky and improve verbiage.

This commit removes the command flag feedback. This commit also swaps the output "update", for "upgrade", making this step closer to other steps for consistency.
2024-10-18 08:26:27 +08:00
Rebecca Turner
9ffdc9649e Add support for Lix (Nix fork) (#952)
Add support for Lix

Lix is a fork of Nix 2.18 focused on maintainability and user
experience. It has a different format for the version, to distinguish it
from CppNix:

    $ nix --version
    nix (Lix, like Nix) 2.91.0

See: <https://lix.systems/>
2024-10-18 08:23:25 +08:00
Rikiub%
a5d4f2eec9 i18n (app.yml): Add Spanish localization (es) (#955)
* Update app.yml

* "es" localization added

* Grammar fixes

* Fix YAML syntax errors

* Fix YAML syntax errors

* Fix duplicated

* Fix duplicate

* Grammar fix

* Grammar fix

* Fix duplicate

* Improve grammar

* Update locales/app.yml

Co-authored-by: SteveLauC <stevelauc@outlook.com>

* Improve Grammar

* Improve Grammar

* Improve Grammar

* Improve Grammar

* Improve Grammar

---------

Co-authored-by: SteveLauC <stevelauc@outlook.com>
2024-10-17 08:04:49 +08:00
Nils
a5df40e01d Refactor config.rs and vagrant.rs files (#949)
* Refactor config.rs and vagrant.rs files

* Refactor config.rs and vagrant.rs files
2024-10-15 17:56:03 +08:00
SteveLauC
0573fc97c6 docs: update release procedure that SECURITY.md should be updated in major release (#946)
docs: update release procedure that SECURITY.md should be updated in major releases
2024-10-14 17:01:22 +08:00
Nils
1ae95f41a1 Update SECURITY.md (#945) 2024-10-14 16:37:15 +08:00
λP.(P izzy)
8a7af2e14d [FIXES #922] properly check for -CURRENT in OpenBSD steps and pass the correct flags to the respective commands (#923)
* [FIXES #922] properly check for -CURRENT in openbsd steps and pass the correct flags

* un-break ctx.config().dry_run() on OpenBSD Step
2024-10-14 08:29:51 +08:00
Nicolas Lorin
c36da89933 ci: add bin pkg to aur (#944) 2024-10-13 21:14:28 +08:00
21 changed files with 787 additions and 60 deletions

View File

@@ -3,9 +3,10 @@
## Standards checklist
- [ ] The PR title is descriptive.
- [ ] The PR title is descriptive
- [ ] I have read `CONTRIBUTING.md`
- [ ] *Optional:* I have tested the code myself
- [ ] If this PR introduces new user-facing messages they are translated
## For new steps

View File

@@ -13,7 +13,7 @@ jobs:
aur-publish:
runs-on: ubuntu-latest
steps:
- name: Publish AUR package
- name: Publish source AUR package
uses: aksh1618/update-aur-package@v1.0.5
with:
tag_version_prefix: v
@@ -21,3 +21,11 @@ jobs:
commit_username: "Thomas Schönauer"
commit_email: t.schoenauer@hgs-wt.at
ssh_private_key: ${{ secrets.AUR_SSH_PRIVATE_KEY }}
- name: Publish binary AUR package
uses: aksh1618/update-aur-package@v1.0.5
with:
tag_version_prefix: v
package_name: topgrade-bin
commit_username: "Thomas Schönauer"
commit_email: t.schoenauer@hgs-wt.at
ssh_private_key: ${{ secrets.AUR_SSH_PRIVATE_KEY }}

View File

@@ -1,6 +0,0 @@
# Containers step
* New default behavior: In the previous versions, if you have both Docker and
Podman installed, Podman will be used by Topgrade. Now the default option
has been changed to Docker. This can be overridden by setting the
`containers.runtime` option in the configuration TOML to "podman".

View File

View File

@@ -129,6 +129,24 @@ $ cargo test
Don't worry about other platforms, we have most of them covered in our CI.
## I18n
If your PR introduces user-facing messages, we need to ensure they are translated.
Please add the translations to [`locales/app.yml`][app_yml]. For simple messages
without arguments (e.g., "hello world"), we can simply translate them according
(Tip: ChatGPT or similar LLMs is good at translation). If a message contains
arguments, e.g., "hello <NAME>", please follow this convention:
```yml
"hello {name}": # key
en: "hello %{name}" # translation
```
Arguments in the key should be in format `{argument_name}`, and they will have
a preceeding `%` when used in translations.
[app_yml]: https://github.com/topgrade-rs/topgrade/blob/main/locales/app.yml
## Some tips
1. Locale

2
Cargo.lock generated
View File

@@ -2770,7 +2770,7 @@ dependencies = [
[[package]]
name = "topgrade"
version = "16.0.1"
version = "16.0.2"
dependencies = [
"cfg-if",
"chrono",

View File

@@ -6,7 +6,7 @@ keywords = ["upgrade", "update"]
license = "GPL-3.0"
repository = "https://github.com/topgrade-rs/topgrade"
rust-version = "1.76.0"
version = "16.0.1"
version = "16.0.2"
authors = ["Roey Darwish Dror <roey.ghost@gmail.com>", "Thomas Schönauer <t.schoenauer@hgs-wt.at>"]
exclude = ["doc/screenshot.gif", "BREAKINGCHANGES_dev.md"]
edition = "2021"

View File

@@ -9,7 +9,11 @@
> If there are breaking changes, the major version number should be increased.
2. Overwrite [`BREAKINGCHANGES`][breaking_changes] with
2. If the major versioin number gets bumped, update [SECURITY.md][SECURITY_file_link].
[SECURITY_file_link]: https://github.com/topgrade-rs/topgrade/blob/main/SECURITY.md
3. Overwrite [`BREAKINGCHANGES`][breaking_changes] with
[`BREAKINGCHANGES_dev`][breaking_changes_dev], and create a new dev file:
```sh'

View File

@@ -6,6 +6,6 @@ We only support the latest major version and each subversion.
| Version | Supported |
| -------- | ------------------ |
| 15.0.x | :white_check_mark: |
| < 15.0 | :x: |
| 16.0.x | :white_check_mark: |
| < 16.0 | :x: |

View File

@@ -103,6 +103,13 @@
# enable_pipupgrade = true ###disabled by default
# pipupgrade_arguments = "-y -u --pip-path pip" ###disabled by default
# For the poetry step, by default, Topgrade skips its update if poetry is not
# installed with the official script. This configuration entry forces Topgrade
# to run the update in this case.
#
# (default: false)
# poetry_force_self_update = true
[composer]
# self_update = true
@@ -172,6 +179,11 @@
# rpm_ostree = false
# For Fedora/CentOS/RHEL Atomic variants, if `bootc` is available and this configuration entry is set to true, use
# it to do the update - Will also supercede rpm-ostree if enabled
# (default: false)
# bootc = false
# nix_arguments = "--flake"
# nix_env_arguments = "--prebuilt-only"
@@ -223,6 +235,11 @@
# use_sudo = true
[deno]
# Upgrade deno executable to the given version.
# version = "stable"
[vim]
# For `vim-plug`, execute `PlugUpdate!` instead of `PlugUpdate`
# force_plug_update = true
@@ -265,3 +282,11 @@
# and the update will be installed system-wide, i.e., available to all users.
# (default: false)
# use_sudo = false
[julia]
# If disabled, Topgrade invokes julia with the --startup-file=no CLI option.
#
# This may be desirable to avoid loading outdated packages with "using" directives
# in the startup file, which might cause the update run to fail.
# (default: true)
# startup_file = true

View File

@@ -2,69 +2,113 @@ _version: 2
"Current system locale is {system_locale}":
en: "Current system locale is %{system_locale}"
es: "La configuración regional del sistema es %{system_locale}"
fr: "Le paramètre linguistique actuel du système est %{system_locale}"
zh_TW: "目前語言為 %{system_locale}"
"Dry running: {program_name} {arguments}":
en: "Dry running: %{program_name} %{arguments}"
es: "Simulando: %{program_name} %{arguments}"
fr: "Simulation : %{program_name} %{arguments}"
zh_TW: "正在模擬 %{program_name} %{arguments} 的執行過程"
"in {directory}":
en: "in %{directory}"
es: "en %{directory}"
fr: "dans %{directory}"
zh_TW: "在 %{directory}"
"Rebooting...":
en: "Rebooting..."
es: "Reiniciando..."
fr: "Redémarrage..."
zh_TW: "正在重新啟動..."
"Plugins upgraded":
en: "Plugins upgraded"
es: "Plugins actualizados"
fr: "Plugins mis à jour"
zh_TW: "已更新所有擴充功能"
"Would self-update":
en: "Would self-update"
es: "Se actualizara automáticamente"
fr: "Se mettrait à jour lui-même"
zh_TW: "將自行更新"
"Pulling":
en: "Pulling"
es: "Extrayendo"
fr: "Récupération"
zh_TW: "正在拉取"
"No Breaking changes":
en: "No Breaking changes"
es: "Sin Cambios Importantes"
fr: "Pas de changement cassant"
zh_TW: "無重大更改"
"Dropping you to shell. Fix what you need and then exit the shell.":
en: "Dropping you to shell. Fix what you need and then exit the shell."
es: "Cambiando al shell. Arregla lo que necesites y luego sal del shell."
fr: "Ouverture d'un shell. Réparez ce dont vous avez besoin et quittez le shell."
zh_TW: "已切換到終端殼層。修復完畢後請退出殼層以繼續。"
"Topgrade launched in a new tmux session":
en: "Topgrade launched in a new tmux session"
es: "Topgrade lanzado en una nueva sesión tmux"
fr: "Topgrade lancé dans une nouvelle session tmux"
zh_TW: "Topgrade 已啟動新 tmux 程序"
'Topgrade upgraded to {version}:\n':
en: 'Topgrade upgraded to %{version}:\n'
es: 'Topgrade actualizado a %{version}:\n'
fr: 'Topgrade mis à jour vers %{version}:\n'
zh_TW: '已將 Topgrade 更新至 %{version}\n'
"Topgrade is up-to-date":
en: "Topgrade is up-to-date"
es: "Topgrade está actualizado"
fr: "Topgrade est à jour"
zh_TW: "Topgrade 為最新版本"
"Updating modules...":
en: "Updating modules..."
es: "Actualizando módulos..."
fr: "Mise à jour des modules..."
zh_TW: "正在更新模組..."
"Powershell Modules Update":
en: "Powershell Modules Update"
es: "Actualización de módulos Powershell"
fr: "Mise à jour des modules Powershell"
zh_TW: "Powershell 模組更新"
"Powershell is not installed":
en: "Powershell is not installed"
es: "Powershell no está instalado"
fr: "Powershell n'est pas installé"
zh_TW: "未安裝 Powershell"
"Error detecting current distribution: {error}":
en: "Error detecting current distribution: %{error}"
es: "Error al detectar la distribución actual: %{error}"
fr: "Erreur lors de la détection de la distribution acutelle: %{error}"
zh_TW: "無法偵測作業系統:%{error}"
"Error: {error}":
en: "Error: %{error}"
es: "Error: %{error}"
fr: "Erreur: %{error}"
zh_TW: "錯誤:%{error}"
"Failed":
en: "Failed"
es: "Fallido"
fr: "Échec"
zh_TW: "失敗"
"pulling":
en: "pulling"
es: "extracción"
fr: "récupérer"
zh_TW: "正在拉取"
"Changed":
en: "Changed"
es: "Cambiado"
fr: "Modifié"
zh_TW: "已更改"
"Up-to-date":
en: "Up-to-date"
es: "Actualizado"
fr: "À jour"
zh_TW: "已為最新版本"
"Self update":
en: "Self update"
es: "Autoactualización"
fr: "Auto mise à jour"
zh_TW: "自行更新"
# The following 2 strings are used in the same sentence
@@ -73,392 +117,679 @@ _version: 2
"Only":
en: "Only"
es: "Solo"
fr: "Seulement"
zh_TW: "將僅"
"updated repositories will be shown...":
en: "updated repositories will be shown..."
es: "se mostrarán los repositorios actualizados..."
fr: "les dépôts mis à jour seront affichés..."
zh_TW: "顯示被更新的 git 來源..."
"because it has no remotes":
en: "because it has no remotes"
es: "porque no tiene fuentes remotas"
fr: "parce qu'il n'a aucun dépôt distant"
zh_TW: "因為其沒有遠端來源"
"Skipping":
en: "Skipping"
es: "Omitiendo"
fr: "Ignoré"
zh_TW: "正在略過"
"Aura(<0.4.6) requires sudo installed to work with AUR packages":
en: "Aura(<0.4.6) requires sudo installed to work with AUR packages"
es: "Aura(<0.4.6) requiere tener sudo instalado para funcionar con paquetes AUR"
fr: "Aura(<0.4.6) nécessite sudo pour fonctionner avec les paquets AUR"
zh_TW: "Aura<0.4.6)依賴 sudo 安裝 AUR 套件"
"Pacman backup configuration files found:":
en: "Pacman backup configuration files found:"
es: "Archivos de respaldo de Pacman encontrados:"
fr: "Fichiers de configuration de sauvegarde de Pacman trouvés :"
zh_TW: "找到 Pacman 設定備份檔:"
"The package audit was successful, but vulnerable packages still remain on the system":
en: "The package audit was successful, but vulnerable packages still remain on the system"
es: "La auditoría del paquete fue exitosa, pero aún quedan paquetes vulnerables en el sistema"
fr: "L'audit des paquets a réussi, mais des paquets vulnérables restent toujours sur le système"
zh_TW: "雖然套件檢測成功,但系統仍然包含危險套件"
"Syncing portage":
en: "Syncing portage"
es: "Sincronizando portage"
fr: "Synchronisation du portage"
zh_TW: "正在同步 portage"
"Finding available software":
en: "Finding available software"
es: "Buscando software disponible"
fr: "Recherche de logiciels disponible"
zh_TW: "正在尋找軟體"
"A system update is available. Do you wish to install it?":
en: "A system update is available. Do you wish to install it?"
es: "Hay una actualización del sistema disponible. ¿Desea instalarla?"
fr: "Une mise à jour du système est disponible. Voulez-vous l'installer ?"
zh_TW: "系統更新已就緒。是否現在安裝?"
"No new software available.":
en: "No new software available."
es: "No hay ningún software nuevo disponible."
fr: "Aucun nouveau logiciel disponible."
zh_TW: "沒有新軟體。"
"No Xcode releases installed.":
en: "No Xcode releases installed."
es: "No hay versiones de Xcode instaladas."
fr: "Aucune version de Xcode installée."
zh_TW: "尚未安裝 Xcode 發行版。"
"Would you like to move the former Xcode release to the trash?":
en: "Would you like to move the former Xcode release to the trash?"
es: "¿Le gustaría mover la versión anterior de Xcode a la papelera?"
fr: "Voulez-vous déplacer la précédente version de Xcode à la corbeille ?"
zh_TW: "是否將舊版 Xcode 移至垃圾桶?"
"New Xcode release detected:":
en: "New Xcode release detected:"
es: "Nueva versión de Xcode detectada:"
fr: "Nouvelle version de Xcode détectée :"
zh_TW: "有新的 Xcode 版本:"
"Would you like to install it?":
en: "Would you like to install it?"
es: "¿Le gustaría instalarlo?"
fr: "Voulez-vous l'installer ?"
zh_TW: "是否現在安裝?"
"No global packages installed":
en: "No global packages installed"
es: "No hay paquetes globales instalados"
fr: "Aucun paquet global n'est installé"
zh_TW: "尚未安裝全域套件"
"Remote Topgrade launched in Tmux":
en: "Remote Topgrade launched in Tmux"
es: "Topgrade remoto lanzado en Tmux"
fr: "Topgrade distant lancé dans Tmux"
zh_TW: "已在 Tmux 中啟動遠端 Topgrade 程序"
"Remote Topgrade launched in an external terminal":
en: "Remote Topgrade launched in an external terminal"
es: "Topgrade remoto iniciado en una terminal externa"
fr: "Topgrade distant lancé dans un terminal externe"
zh_TW: "已在新終端機視窗中啟動遠端 Topgrade"
"Collecting Vagrant boxes":
en: "Collecting Vagrant boxes"
es: "Recolectando cajas Vagrant"
fr: "Collecte des boîtes Vagrant"
zh_TW: "正在蒐集 Vagrant 容器"
"No Vagrant directories were specified in the configuration file":
en: "No Vagrant directories were specified in the configuration file"
es: "No se especificaron directorios Vagrant en el archivo de configuración"
fr: "Aucun répertoire Vagrant n'est spécifié dans le fichier de configuration"
zh_TW: "尚未在設定檔中指定 Vagrant 資料夾"
"Vagrant boxes":
en: "Vagrant boxes"
es: "Cajas Vagrant"
fr: "Boîtes Vagrant"
zh_TW: "Vagrant 容器"
"No outdated boxes":
en: "No outdated boxes"
es: "Sin cajas obsoletas"
fr: "Aucune boîte obsolète"
zh_TW: "未有需要更新的容器"
"Summary":
en: "Summary"
es: "Resumen"
fr: "Résumé"
zh_TW: "結果"
"Topgrade finished with errors":
en: "Topgrade finished with errors"
es: "Topgrade finalizado con errores"
fr: "Topgrade terminé avec des erreurs"
zh_TW: "Topgrade 執行部分成功"
"Topgrade finished successfully":
en: "Topgrade finished successfully"
es: "Topgrade finalizó exitosamente"
fr: "Topgrade terminé avec succès"
zh_TW: "Topgrade 執行成功"
"Topgrade {version_str} Breaking Changes":
en: "Topgrade %{version_str} Breaking Changes"
es: "Topgrade %{version_str} Cambios Importantes"
fr: "Topgrade %{version_str} Changements Cassants"
zh_TW: "Topgrade %{version_str} 重大更改"
"Path {path} expanded to {expanded}":
en: "Path %{path} expanded to %{expanded}"
es: "Ruta %{path} expandida a %{expanded}"
fr: "Le chemin %{path} a été transformé en %{expanded}"
zh_TW: "已擴展 %{path} 至 %{expanded}"
"Path {path} doesn't exist":
en: "Path %{path} doesn't exist"
es: "La ruta %{path} no existe"
fr: "Le chemin %{path} n'existe pas"
zh_TW: "路徑 %{path} 不存在"
"Cannot find {binary_name} in PATH":
en: "Cannot find %{binary_name} in PATH"
es: "No se pudo encontrar %{binary_name} en PATH"
fr: "Impossible de trouver %{binary_name} dans le PATH"
zh_TW: "在 $PATH 中找不到 %{binary_name} 執行檔"
"Failed to get a UTF-8 encoded hostname":
en: "Failed to get a UTF-8 encoded hostname"
es: "Error al obtener un nombre de host codificado en UTF-8"
fr: "Échec de l'obtention d'un nom d'hôte encodé en UTF-8"
zh_TW: "無法取得 UTF-8 編碼的主機名稱"
"Failed to get hostname: {err}":
en: "Failed to get hostname: %{err}"
es: "Error al obtener el nombre del host: %{err}"
fr: "Échec de l'obtention d'un nom d'hôte: %{err}"
zh_TW: "無法取得主機名稱:%{err}"
"{python} is a Python 2, skip.":
en: "%{python} is a Python 2, skip."
es: "%{python} es Python 2, omitiendo."
fr: "%{python} est un Python 2, ignoré."
zh_TW: "%{python} 是 Python 2略過。"
"{python} is a Python shim, skip.":
en: "%{python} is a Python shim, skip."
es: "%{python} es una corrección de Python, omitiendo."
fr: "%{python} est un shim Python, ignoré."
zh_TW: "%{python} 是 Python shim略過。"
"{key} failed:":
en: "%{key} failed:"
es: "%{key} ha fallado:"
fr: "%{key} a échoué :"
zh_TW: "%{key} 失敗:"
"{step_name} failed":
en: "%{step_name} failed"
es: "%{step_name} fallido"
fr: "%{step_name} a échoué"
zh_TW: "%{step_name} 失敗"
"DragonFly BSD Packages":
en: "DragonFly BSD Packages"
es: "Paquetes BSD de DragonFly"
fr: "Paquets DragonFly BSD"
zh_TW: "DragonFly BSD 套件"
"DragonFly BSD Audit":
en: "DragonFly BSD Audit"
es: "Auditoría de DragonFly BSD"
fr: "Audit de DragonFly BSD"
zh_TW: "DragonFly BSD 紀錄"
"FreeBSD Update":
en: "FreeBSD Update"
es: "Actualización de FreeBSD"
fr: "Mise à jour de FreeBSD"
zh_TW: "FreeBSD 更新"
"FreeBSD Packages":
en: "FreeBSD Packages"
es: "Paquetes FreeBSD"
fr: "Paquets FreeBSD"
zh_TW: "FreeBSD 套件"
"FreeBSD Audit":
en: "FreeBSD Audit"
es: "Auditoría FreeBSD"
fr: "Audit de FreeBSD"
zh_TW: "FreeBSD 紀錄"
"System update":
en: "System update"
es: "Actualización del sistema"
fr: "Mise à jour du système"
zh_TW: "系統更新"
"needrestart will be ran by the package manager":
en: "needrestart will be ran by the package manager"
es: "needrestart será ejecutado por el administrador de paquetes"
fr: "needrestart sera exécuté par le gestionnaire de paquets"
zh_TW: "needrestart 將被套件管理員執行"
"Check for needed restarts":
en: "Check for needed restarts"
es: "Comprobando si es necesario reiniciar el sistema"
fr: "Vérification des redémarrages nécessaires"
zh_TW: "正在檢查是否需要重新啟動系統"
"Should not run in WSL":
en: "Should not run in WSL"
es: "No se debe ejecutar en WSL"
fr: "Ne doit pas être exécuté dans WSL"
zh_TW: "不該在 WSL 中執行"
"Firmware upgrades":
en: "Firmware upgrades"
es: "Actualizaciones de firmware"
fr: "Mises à jour du firmware"
zh_TW: "韌體更新"
"Flatpak System Packages":
en: "Flatpak System Packages"
es: "Paquetes del sistema Flatpak"
fr: "Paquets système Flatpak"
zh_TW: "Flatpak 系統套件"
"Snapd socket does not exist":
en: "Snapd socket does not exist"
es: "El socket Snapd no existe"
fr: "Le socket Snapd n'existe pas"
zh_TW: "找不到 Snapd 程序"
"You need to specify at least one container":
en: "You need to specify at least one container"
es: "Necesita especificar al menos un contenedor"
fr: "Vous devez spécifier au moins un conteneur"
zh_TW: "必須指定至少一個容器"
"Skipped in --yes":
en: "Skipped in --yes"
es: "Omitido por --yes"
fr: "Ignoré avec --yes"
zh_TW: "指定 --yes略過"
"Configuration update":
en: "Configuration update"
es: "Actualización de configuración"
fr: "Mise à jour de la configuration"
zh_TW: "設定更新"
"Going to execute `waydroid upgrade`, which would STOP the running container, is this ok?":
en: "Going to execute `waydroid upgrade`, which would STOP the running container, is this ok?"
es: "Se ejecutará `waydroid update`, lo que DETENDRÁ el contenedor en ejecución. ¿Está bien?"
fr: "`waydroid upgrade` va s'exécuter, ce qui ARRÊTERA le conteneur en cours d'exécution, est-ce ok ?"
zh_TW: "將略過 `waydroid upgrade`,並且「停止」執行容器。是否繼續?"
"Skip the Waydroid step because the user don't want to proceed":
en: "Skip the Waydroid step because the user don't want to proceed"
es: "Omitiendo el paso de Waydroid debido a que el usuario no quiere continuar"
fr: "Passer l'étape Waydroid car l'utilisateur ne souhaite pas l'exécuter"
zh_TW: "使用者指定略過 Waydroid 程序"
"macOS App Store":
en: "macOS App Store"
es: "Tienda de aplicaciones macOS"
fr: "macOS App Store"
zh_TW: "macOS App Store"
"macOS system update":
en: "macOS system update"
es: "Actualización del sistema macOS"
fr: "Mise à jour du système macOS"
zh_TW: "macOS 系統更新"
"OpenBSD Update":
en: "OpenBSD Update"
es: "Actualización de OpenBSD"
fr: "Mise à jour d'OpenBSD"
zh_TW: "OpenBSD 更新"
"OpenBSD Packages":
en: "OpenBSD Packages"
es: "Paquetes OpenBSD"
fr: "Paquets OpenBSD"
zh_TW: "OpenBSD 套件"
"`fisher` is not defined in `fish`":
en: "`fisher` is not defined in `fish`"
es: "`fisher` no está definido en `fish`"
fr: "`fisher` n'est pas reconnu dans `fish`"
zh_TW: "`fisher` 未在 `fish` 中指定"
"`fish_plugins` path doesn't exist: {err}":
en: "`fish_plugins` path doesn't exist: %{err}"
es: "La ruta `fish_plugins` no existe: %{err}"
fr: "Le chemin `fish_plugins` n'existe pas : %{err}"
zh_TW: "不存在 `fish_plugins` 路徑:%{err}"
"`fish_update_completions` is not available":
en: "`fish_update_completions` is not available"
es: "`fish_update_completions` no está disponible"
fr: "`fish_update_completions` n'est pas disponible"
zh_TW: "無法使用 `fish_update_completions`"
"Desktop doest not appear to be gnome":
en: "Desktop doest not appear to be gnome"
es: "El escritorio no parece ser Gnome"
fr: "Le bureau ne semble pas être Gnome"
zh_TW: "桌面環境不是 Gnome"
"Gnome shell extensions are unregistered in DBus":
en: "Gnome shell extensions are unregistered in DBus"
es: "Las extensiones de Gnome Shell no están registradas en DBus"
fr: "Les extensions de Gnome Shell ne sont pas enregistrées dans DBus"
zh_TW: "Gnome Shell 擴充功能在 DBus 中未被註冊"
"Gnome Shell extensions":
en: "Gnome Shell extensions"
es: "Extensiones de Gnome Shell"
fr: "Extensions de Gnome Shell"
zh_TW: "Gnome Shell 擴充功能"
"Not a custom brew for macOS":
en: "Not a custom brew for macOS"
es: "No es un brew personalizado para macOS"
fr: "Pas une version de brew personnalisée pour macOS"
zh_TW: "不是專門的 macOS brew"
"Guix Pull Failed, Skipping":
en: "Guix Pull Failed, Skipping"
es: "Guix Pull Fallido, omitiendo"
fr: "Échec de Guix Pull, ignoré"
zh_TW: "Guix 拉取失敗,略過"
"Nix-darwin on macOS must be upgraded via darwin-rebuild switch":
en: "Nix-darwin on macOS must be upgraded via darwin-rebuild switch"
es: "Nix-darwin en macOS debe actualizarse mediante el interruptor darwin-rebuild"
fr: "Nix-darwin sur macOS doit être mis à niveau via l'option darwin-rebuild"
zh_TW: "Nix-darwin 在 macOS 上必須使用 darwin-rebuild 更新"
"`nix upgrade-nix` can only be used on macOS or non-NixOS Linux":
en: "`nix upgrade-nix` can only be used on macOS or non-NixOS Linux"
es: "`nix update-nix` solo puede usarse en macOS o Linux que no sea NixOS"
fr: "`nix upgrade-nix` ne peut être utilisée que sur macOS ou Linux non-NixOS"
zh_TW: "`nix upgrade-nix` 僅能在 macOS 或非 NixOS 的 Linux 上使用"
"`nix upgrade-nix` cannot be run when Nix is installed in a profile":
en: "`nix upgrade-nix` cannot be run when Nix is installed in a profile"
es: "`nix Upgrade-nix` no puede ejecutarse cuando Nix está instalado en un perfil"
fr: "`nix upgrade-nix` ne peut pas être exécutée lorsque Nix est installé dans un profil"
zh_TW: "`nix upgrade-nix` 無法在已安裝 Nix 使用者環境的系統上使用"
"Nix (self-upgrade)":
en: "Nix (self-upgrade)"
es: "Nix (autoactualización)"
fr: "Nix (auto mise à niveau)"
zh_TW: "Nix自行更新"
"Pyenv is installed, but $PYENV_ROOT is not set correctly":
en: "Pyenv is installed, but $PYENV_ROOT is not set correctly"
es: "Pyenv está instalado, pero $PYENV_ROOT no está configurado correctamente"
fr: "Pyenv est installé, mais $PYENV_ROOT n'est pas défini correctement"
zh_TW: "已安裝 Pyenv 但尚未正確設定 $PYENV_ROOT"
"pyenv is not a git repository":
en: "pyenv is not a git repository"
es: "pyenv no es un repositorio git"
fr: "pyenv n'est pas un dépôt Git"
zh_TW: "pyenv 不是 git 來源"
"Bun Packages":
en: "Bun Packages"
es: "Paquetes Bun"
fr: "Paquets Bun"
zh_TW: "Bun 套件"
"WSL not installed":
en: "WSL not installed"
es: "WSL no instalado"
fr: "WSL n'est pas installé"
zh_TW: "未安裝 WSL"
"Update WSL":
en: "Update WSL"
es: "Actualizando WSL"
fr: "Mise à jour du WSL"
zh_TW: "更新 WSL"
"Could not find Topgrade installed in WSL":
en: "Could not find Topgrade installed in WSL"
es: "Topgrade no se ha instalado dentro de WSL"
fr: "Impossible de trouver Topgrade installé dans WSL"
zh_TW: "尚未在 WSL 內安裝 Topgrade"
"Consider installing PSWindowsUpdate as the use of Windows Update via USOClient is not supported.":
en: "Consider installing PSWindowsUpdate as the use of Windows Update via USOClient is not supported."
es: "Considere instalar PSWindowsUpdate ya que no se admite el uso de Windows Update a través de USOClient."
fr: "Envisagez d'installer PSWindowsUpdate car l'utilisation de Windows Update via USOClient n'est pas prise en charge."
zh_TW: "目前不支援使用 USOClient 管理 Windows 更新。建議安裝 PSWindowsUpdate。"
"USOClient not supported.":
en: "USOClient not supported."
es: "USOClient no es admitido."
fr: "USOClient n'est pas pris en charge."
zh_TW: "不支援 USOClient。"
"Connecting to {hostname}...":
en: "Connecting to %{hostname}..."
es: "Conectándose a %{hostname}..."
fr: "Connexion à %{hostname}..."
zh_TW: "正在連接 %{hostname}..."
"Skipping powered off box {vagrant_box}":
en: "Skipping powered off box %{vagrant_box}"
es: "Omitiendo el contenedor apagado %{vagrant_box}"
fr: "Ingorer la boîte éteinte %{vagrant_box}"
zh_TW: "正在略過已關機的容器 %{vagrant_box}"
"`{repo_tag}` for `{platform}`":
en: "`%{repo_tag}` for `%{platform}`"
es: "`%{repo_tag}` para `%{platform}`"
fr: "`%{repo_tag}` pour `%{platform}`"
zh_TW: "`%{repo_tag}` 給 `%{platform}`"
"Containers":
en: "Containers"
es: "Contenedores"
fr: "Conteneurs"
zh_TW: "容器"
"Emacs directory does not exist":
en: "Emacs directory does not exist"
es: "El directorio Emacs no existe"
fr: "Le répertoire Emacs n'existe pas"
zh_TW: "找不到 Emacs 資料夾"
"Error getting the composer directory: {error}":
en: "Error getting the composer directory: %{error}"
es: "Error al obtener el directorio de composer: %{error}"
fr: "Erreur lors de la récupération du répertoire de Composer : %{error}"
zh_TW: "無法取得 composer 資料夾:%{error}"
"Composer directory {composer_home} isn't a descendant of the user's home directory":
en: "Composer directory %{composer_home} isn't a descendant of the user's home directory"
es: "El directorio de composer %{composer_home} no es descendiente del directorio de inicio del usuario"
fr: "Le répertoire de Composer %{composer_home} n'est pas un descendant du répertoire home de l'utilisateur"
zh_TW: "Composer 資料夾 %{composer_home} 不在家目錄下"
"Composer":
en: "Composer"
es: "Composer"
fr: "Composer"
zh_TW: "Composer"
"Error running `dotnet tool list`. This is expected when a dotnet runtime is installed but no SDK.":
en: "Error running `dotnet tool list`. This is expected when a dotnet runtime is installed but no SDK."
es: "Error al ejecutar `dotnet tool list`. Esto es lo esperado cuando se instala un entorno de ejecución dotnet pero no un SDK."
fr: "Erreur lors de l'exécution de `dotnet tool list`. Ce comportement est attendu lorsque le runtime dotnet est installé mais pas le SDK."
zh_TW: "執行 `dotnet tool list` 失敗。已安裝 dotnet 執行環境但未安裝 SDK"
"No dotnet global tools installed":
en: "No dotnet global tools installed"
es: "No hay herramientas globales dotnet instaladas"
fr: "Aucun outil global dotnet installé"
zh_TW: "尚未安裝全域 dotnet 工具"
"Racket Package Manager":
en: "Racket Package Manager"
es: "Administrador de paquetes Racket"
fr: "Gestionnaire de paquets Racket"
zh_TW: "Racket 套件管理員"
"GH failed":
en: "GH failed"
es: "GH fallido"
fr: "Échec de GH"
zh_TW: "GH 失敗"
"GitHub CLI Extensions":
en: "GitHub CLI Extensions"
es: "Extensiones de GitHub CLI"
fr: "Extensions de Github CLI"
zh_TW: "GitHub CLI 擴充功能"
"Julia Packages":
en: "Julia Packages"
es: "Paquetes Julia"
fr: "Paquets Julia"
zh_TW: "Julia 套件"
"Update ClamAV Database(FreshClam)":
en: "Update ClamAV Database(FreshClam)"
es: "Actualizando base de datos ClamAV (FreshClam)"
fr: "Mise à jour de la base de données ClamAV (FreshClam)"
zh_TW: "更新 ClamAV 資料庫FreshClam"
"Path {pattern} did not contain any git repositories":
en: "Path %{pattern} did not contain any git repositories"
es: "La ruta %{pattern} no contenía ningún repositorio git"
fr: "Le chemin %{pattern} ne contenait aucun dépôt Git"
zh_TW: "路徑 %{pattern} 中沒有任何 git 來源"
"No repositories to pull":
en: "No repositories to pull"
es: "No hay repositorios que extraer"
fr: "Aucun dépôt à récupérer"
zh_TW: "沒有來源可以拉取"
"Git repositories":
en: "Git repositories"
es: "Repositorios Git"
fr: "Dépôts Git"
zh_TW: "Git 來源"
"Would pull {repo}":
en: "Would pull %{repo}"
es: "Extrayendo %{repo}"
fr: "Tirerait %{repo}"
zh_TW: "拉取 %{repo}"
# aka npm
"Node Package Manager":
en: "Node Package Manager"
es: "Node Package Manager (npm)"
fr: "Gestionnaire de paquets Node (npm)"
zh_TW: "Node 套件管理員npm"
# aka pnpm
"Performant Node Package Manager":
en: "Performant Node Package Manager"
es: "Performant Node Package Manager (pnpm)"
fr: "Gestionnaire de paquets Node performant (pnpm)"
zh_TW: "效能 Node 套件管理員pnpm"
"Yarn Package Manager":
en: "Yarn Package Manager"
es: "Administrador de paquetes Yarn"
fr: "Gestionnaire de paquets Yarn"
zh_TW: "Yarn 套件管理員"
"Deno installed outside of .deno directory":
en: "Deno installed outside of .deno directory"
es: "Deno está instalado fuera del directorio .deno"
fr: "Deno est installé en dehors du répertoire .deno"
zh_TW: "Deno 安裝在 .deno 資料夾外"
"The Ultimate vimrc":
en: "The Ultimate vimrc"
es: "El vimrc definitivo (The Ultimate vimrc)"
fr: "The Ultimate vimrc"
zh_TW: "終極 vimrcThe Ultimate vimrc"
"vim binary might be actually nvim":
en: "vim binary might be actually nvim"
es: "el binario vim puede ser nvim"
fr: "Le binaire vim pourrait être en réalité nvim"
zh_TW: "vim 執行檔可能為 nvim"
"`{process}` failed: {exit_status}":
en: "`%{process}` failed: %{exit_status}"
es: "`%{process}` falló: %{exit_status}"
fr: "`%{process}` a échoué : %{exit_status}"
zh_TW: "`%{process}` 失敗:%{exit_status}"
"`{process}` failed: {exit_status} with {output}":
en: "`%{process}` failed: %{exit_status} with %{output}"
es: "`%{process}` falló: %{exit_status} con %{output}"
fr: "`%{process}` a échoué : %{exit_status} avec %{output}"
zh_TW: "`%{process}` 失敗:%{exit_status} 伴隨 %{output}"
"Unknown Linux Distribution":
en: "Unknown Linux Distribution"
es: "Distribución de Linux desconocida"
fr: "Distribution Linux inconnue"
zh_TW: "未知 Linux"
'File "/etc/os-release" does not exist or is empty':
en: 'File "/etc/os-release" does not exist or is empty'
es: 'El archivo "/etc/os-release" no existe o está vacío'
fr: "Le fichier \"/etc/os-release\" n'existe pas ou est vide"
zh_TW: '「/etc/os-release」不存在或為空'
"Failed getting the system package manager":
en: "Failed getting the system package manager"
es: "Error al obtener el administrador de paquetes del sistema"
fr: "Échec de l'obtention du gestionnaire de paquets système"
zh_TW: "偵測系統套件管理員失敗"
"A step failed":
en: "A step failed"
es: "Un paso fallido"
fr: "Une étape a échouée"
zh_TW: "某步驟執行失敗"
"Dry running":
en: "Dry running"
es: "Simulando"
fr: "Simulation"
zh_TW: "模擬執行"
"Topgrade Upgraded":
en: "Topgrade Upgraded"
es: "Topgrade Actualizado"
fr: "Topgrade mis à jour"
zh_TW: "已更新 Topgrade"
# Summary texts
"OK":
en: "OK"
es: "OK"
fr: "OK"
zh_TW: "成功"
"FAILED":
en: "FAILED"
es: "FALLIDO"
fr: "ÉCHEC"
zh_TW: "失敗"
"IGNORED":
en: "IGNORED"
es: "IGNORADO"
fr: "IGNORÉ"
zh_TW: "忽略"
"SKIPPED":
en: "SKIPPED"
es: "OMITIDO"
fr: "PASSÉ"
zh_TW: "略過"
# 'Y' and 'N' have to stay the same characters. Eg for German the translation
# would look sth like "(Y) Ja / (N) Nein"
"(Y)es/(N)o":
en: "(Y)es/(N)o"
es: "(Y) Si / (N) No"
fr: "(Y) Oui / (N) Non"
zh_TW: "(Y)是/(N)否"
# 'y', 'N', 's', 'q' have to stay the same throughout all translations.
# Eg German would look like "(y) Wiederholen / (N) Nein / (s) Konsole / (q) Beenden"
"Retry? (y)es/(N)o/(s)hell/(q)uit":
en: "Retry? (y)es/(N)o/(s)hell/(q)uit"
es: "¿Reintentar? (y) Si / (N) No / (s) Shell / (q) Salir"
fr: "Réessayer ? (y) Oui / (N) Non / (s) Shell / (q) Quitter"
zh_TW: "再試一次? (y)是/(N)否/(s)殼層/(q)退出"
# 'R', 'S', 'Q' have to stay the same throughout all translations. Eg German would look like "\n(R) Neustarten\n(S) Konsole\n(Q) Beenden"
'\n(R)eboot\n(S)hell\n(Q)uit':
en: '\n(R)eboot\n(S)hell\n(Q)uit'
es: "\n(R) Reiniciar\n(S) Shell\n(Q) Salir"
fr: '\n(R) Redémarrer\n(S) Shell\n(Q) Quitter'
zh_TW: '\n(R)重新啟動\n(S)殼層\n(Q)退出'
"Require sudo or counterpart but not found, skip":
en: "Require sudo or counterpart but not found, skip"
es: "Se requiere sudo o su equivalente pero no ha sido encontrado, omitiendo"
fr: "Nécessite sudo ou un équivalent mais n'a pas été trouvé, passé"
zh_TW: "找不到權限管理程式sudo 等),略過"
"sudo as user '{user}'":
en: "sudo as user '%{user}'"
es: "sudo como usuario '%{user}'"
fr: "sudo en tant qu'utilisateur '%{user}'"
zh_TW: "sudo 以使用者 '%{user}'"
"Updating aqua ...":
en: "Updating aqua ..."
es: "Actualizando aqua..."
fr: "Mise à jour d'aqua..."
zh_TW: "正在更新 aqua..."
"Updating aqua installed cli tools ...":
en: "Updating aqua installed cli tools ..."
es: "Actualizando las herramientas CLI instaladas en aqua ..."
fr: "Mise à jour des outils cli installés d'aqua..."
zh_TW: "正在更新 aqua 安裝的命令行介面工具..."
"Updating Volta packages...":
en: "Updating Volta packages..."
es: "Actualizando paquetes Volta..."
fr: "Mise à jour des paquets Volta..."
zh_TW: "正在更新 Volta 套件..."
"No packages installed with Volta":
en: "No packages installed with Volta"
es: "No hay paquetes instalados con Volta"
fr: "Aucun paquet installé avec Volta"
zh_TW: "沒有任何 Volta 套件"
"pyenv-update plugin is not installed":
en: "pyenv-update plugin is not installed"
es: "El plugin pyenv-update no está instalado"
fr: "Le plugin pyenv-update n'est pas installé"
zh_TW: "尚未安裝 pyenv-update 擴充功能"
"Respawning...":
en: "Respawning..."
es: "Reapareciendo..."
fr: "Relancement..."
zh_TW: "正在重新生成..."
"Could not find Topgrade in any WSL disribution":
en: "Could not find Topgrade in any WSL disribution"
es: "No se pudo encontrar Topgrade en ninguna distribución WSL"
fr: "Impossible de trouver Topgrade dans aucune distribution WSL"
zh_TW: "在所有 WSL 中找不到 Topgrade"
"Windows Update":
en: "Windows Update"
es: "Actualización de Windows"
fr: "Mise à jour de Windows"
zh_TW: "Windows 更新"
"Would check if OpenBSD is -current":
en: "Would check if OpenBSD is -current"
es: "Comprobaría si OpenBSD está en -current"
fr: "Vérifierait si OpenBSD est à -curent"
zh_TW: "會檢查 OpenBSD 是否為 -current"
"Would upgrade the OpenBSD system":
en: "Would upgrade the OpenBSD system"
es: "Actualizaría el sistema OpenBSD"
fr: "Mettrait à jour le système OpenBSD"
zh_TW: "會升級 OpenBSD 系統"
"Would upgrade OpenBSD packages":
en: "Would upgrade OpenBSD packages"
es: "Actualizaría los paquetes de OpenBSD"
fr: "Mettrait à jour les paquets OpenBSD"
zh_TW: "會升級 OpenBSD 套件"
"Microsoft Store":
en: "Microsoft Store"
es: "Tienda de Microsoft"
fr: "Microsoft Store"
zh_TW: "Microsoft Store"
"Scanning for updates...":
en: "Scanning for updates..."
es: "Buscando actualizaciones..."
fr: "Recherche de mises à jour..."
zh_TW: "正在掃描更新..."
"Success, Microsoft Store apps are being updated in the background":
en: "Success, Microsoft Store apps are being updated in the background"
es: "Éxito, las aplicaciones de Microsoft Store se están actualizando en segundo plano"
fr: "Succès, les applications du Microsoft Store sont en cours de mise à jour en arrière plan"
zh_TW: "成功Microsoft Store 應用程式正在後台更新"
"Unable to update Microsoft Store apps, manual intervention is required":
en: "Unable to update Microsoft Store apps, manual intervention is required"
es: "No se pueden actualizar las aplicaciones de Microsoft Store, se requiere intervención manual"
fr: "Impossible de mettre à jour les applications du Microsoft Store, une intervention manuelle est nécessaire"
zh_TW: "無法更新 Microsoft Store 應用,需手動幹預"

View File

@@ -111,6 +111,7 @@ pub enum Step {
Mas,
Maza,
Micro,
MicrosoftStore,
Mise,
Myrepos,
Nix,
@@ -228,6 +229,7 @@ pub struct Python {
enable_pip_review_local: Option<bool>,
enable_pipupgrade: Option<bool>,
pipupgrade_arguments: Option<String>,
poetry_force_self_update: Option<bool>,
}
#[derive(Deserialize, Default, Debug, Merge)]
@@ -254,6 +256,13 @@ pub struct NPM {
use_sudo: Option<bool>,
}
#[derive(Deserialize, Default, Debug, Merge)]
#[serde(deny_unknown_fields)]
#[allow(clippy::upper_case_acronyms)]
pub struct Deno {
version: Option<String>,
}
#[derive(Deserialize, Default, Debug, Merge)]
#[serde(deny_unknown_fields)]
#[allow(clippy::upper_case_acronyms)]
@@ -350,6 +359,7 @@ pub struct Linux {
redhat_distro_sync: Option<bool>,
suse_dup: Option<bool>,
rpm_ostree: Option<bool>,
bootc: Option<bool>,
#[merge(strategy = crate::utils::merge_strategies::string_append_opt)]
emerge_sync_flags: Option<String>,
@@ -444,6 +454,12 @@ pub struct Lensfun {
use_sudo: Option<bool>,
}
#[derive(Deserialize, Default, Debug, Merge)]
#[serde(deny_unknown_fields)]
pub struct JuliaConfig {
startup_file: Option<bool>,
}
#[derive(Deserialize, Default, Debug, Merge)]
#[serde(deny_unknown_fields)]
/// Configuration file
@@ -490,6 +506,9 @@ pub struct ConfigFile {
#[merge(strategy = crate::utils::merge_strategies::inner_merge_opt)]
yarn: Option<Yarn>,
#[merge(strategy = crate::utils::merge_strategies::inner_merge_opt)]
deno: Option<Deno>,
#[merge(strategy = crate::utils::merge_strategies::inner_merge_opt)]
vim: Option<Vim>,
@@ -507,6 +526,9 @@ pub struct ConfigFile {
#[merge(strategy = crate::utils::merge_strategies::inner_merge_opt)]
lensfun: Option<Lensfun>,
#[merge(strategy = crate::utils::merge_strategies::inner_merge_opt)]
julia: Option<JuliaConfig>,
}
fn config_directory() -> PathBuf {
@@ -1437,6 +1459,15 @@ impl Config {
.unwrap_or(false)
}
/// Use bootc in *when bootc is detected* (default: false)
pub fn bootc(&self) -> bool {
self.config_file
.linux
.as_ref()
.and_then(|linux| linux.bootc)
.unwrap_or(false)
}
/// Determine if we should ignore failures for this step
pub fn ignore_failure(&self, step: Step) -> bool {
self.config_file
@@ -1525,6 +1556,10 @@ impl Config {
.unwrap_or(false)
}
pub fn deno_version(&self) -> Option<&str> {
self.config_file.deno.as_ref().and_then(|deno| deno.version.as_deref())
}
#[cfg(target_os = "linux")]
pub fn firmware_upgrade(&self) -> bool {
self.config_file
@@ -1566,12 +1601,11 @@ impl Config {
}
pub fn enable_pipupgrade(&self) -> bool {
return self
.config_file
self.config_file
.python
.as_ref()
.and_then(|python| python.enable_pipupgrade)
.unwrap_or(false);
.unwrap_or(false)
}
pub fn pipupgrade_arguments(&self) -> &str {
self.config_file
@@ -1581,20 +1615,25 @@ impl Config {
.unwrap_or("")
}
pub fn enable_pip_review(&self) -> bool {
return self
.config_file
self.config_file
.python
.as_ref()
.and_then(|python| python.enable_pip_review)
.unwrap_or(false);
.unwrap_or(false)
}
pub fn enable_pip_review_local(&self) -> bool {
return self
.config_file
self.config_file
.python
.as_ref()
.and_then(|python| python.enable_pip_review_local)
.unwrap_or(false);
.unwrap_or(false)
}
pub fn poetry_force_self_update(&self) -> bool {
self.config_file
.python
.as_ref()
.and_then(|python| python.poetry_force_self_update)
.unwrap_or(false)
}
pub fn display_time(&self) -> bool {
@@ -1620,6 +1659,14 @@ impl Config {
.and_then(|lensfun| lensfun.use_sudo)
.unwrap_or(false)
}
pub fn julia_use_startup_file(&self) -> bool {
self.config_file
.julia
.as_ref()
.and_then(|julia| julia.startup_file)
.unwrap_or(true)
}
}
#[cfg(test)]

View File

@@ -206,6 +206,9 @@ fn run() -> Result<()> {
runner.execute(Step::Scoop, "Scoop", || windows::run_scoop(&ctx))?;
runner.execute(Step::Winget, "Winget", || windows::run_winget(&ctx))?;
runner.execute(Step::System, "Windows update", || windows::windows_update(&ctx))?;
runner.execute(Step::MicrosoftStore, "Microsoft Store", || {
windows::microsoft_store(&ctx)
})?;
}
#[cfg(target_os = "linux")]

View File

@@ -1,5 +1,6 @@
#![allow(unused_imports)]
use std::ffi::OsStr;
use std::path::PathBuf;
use std::process::Command;
use std::{env, path::Path};
@@ -908,10 +909,15 @@ pub fn update_julia_packages(ctx: &ExecutionContext) -> Result<()> {
print_separator(t!("Julia Packages"));
ctx.run_type()
.execute(julia)
.args(["-e", "using Pkg; Pkg.update()"])
.status_checked()
let mut executor = ctx.run_type().execute(julia);
executor.arg(if ctx.config().julia_use_startup_file() {
"--startup-file=yes"
} else {
"--startup-file=no"
});
executor.args(["-e", "using Pkg; Pkg.update()"]).status_checked()
}
pub fn run_helm_repo_update(ctx: &ExecutionContext) -> Result<()> {
@@ -1024,23 +1030,108 @@ pub fn run_lensfun_update_data(ctx: &ExecutionContext) -> Result<()> {
pub fn run_poetry(ctx: &ExecutionContext) -> Result<()> {
let poetry = require("poetry")?;
#[cfg(unix)]
fn get_interpreter(poetry: &PathBuf) -> Result<PathBuf> {
use std::os::unix::ffi::OsStrExt;
let script = fs::read(poetry)?;
if let Some(r) = script.iter().position(|&b| b == b'\n') {
let first_line = &script[..r];
if first_line.starts_with(b"#!") {
return Ok(OsStr::from_bytes(&first_line[2..]).into());
}
}
Err(eyre!("Could not find shebang"))
}
#[cfg(windows)]
fn get_interpreter(poetry: &PathBuf) -> Result<PathBuf> {
let data = fs::read(poetry)?;
// https://bitbucket.org/vinay.sajip/simple_launcher/src/master/compare_launchers.py
let pos = match data.windows(4).rposition(|b| b == b"PK\x05\x06") {
Some(i) => i,
None => return Err(eyre!("Not a ZIP archive")),
};
let cdr_size = match data.get(pos + 12..pos + 16) {
Some(b) => u32::from_le_bytes(b.try_into().unwrap()) as usize,
None => return Err(eyre!("Invalid CDR size")),
};
let cdr_offset = match data.get(pos + 16..pos + 20) {
Some(b) => u32::from_le_bytes(b.try_into().unwrap()) as usize,
None => return Err(eyre!("Invalid CDR offset")),
};
if pos < cdr_size + cdr_offset {
return Err(eyre!("Invalid ZIP archive"));
}
let arc_pos = pos - cdr_size - cdr_offset;
let shebang = match data[..arc_pos].windows(2).rposition(|b| b == b"#!") {
Some(l) => &data[l + 2..arc_pos - 1],
None => return Err(eyre!("Could not find shebang")),
};
// shebang line is utf8
Ok(std::str::from_utf8(shebang)?.into())
}
if ctx.config().poetry_force_self_update() {
debug!("forcing poetry self update");
} else {
let interpreter = match get_interpreter(&poetry) {
Ok(p) => p,
Err(e) => {
return Err(SkipStep(format!("Could not find interpreter for {}: {}", poetry.display(), e)).into())
}
};
debug!("poetry interpreter: {}", interpreter.display());
let check_official_install_script =
"import sys; from os import path; print('Y') if path.isfile(path.join(sys.prefix, 'poetry_env')) else print('N')";
let output = Command::new(&interpreter)
.args(["-c", check_official_install_script])
.output_checked_utf8()?;
let stdout = output.stdout.trim();
let official_install = match stdout {
"N" => false,
"Y" => true,
_ => unreachable!("unexpected output from `check_official_install_script`"),
};
debug!("poetry is official install: {}", official_install);
if !official_install {
return Err(SkipStep("Not installed with the official script".to_string()).into());
}
}
print_separator("Poetry");
ctx.run_type().execute(poetry).args(["self", "update"]).status_checked()
ctx.run_type()
.execute(&poetry)
.args(["self", "update"])
.status_checked()
}
pub fn run_uv(ctx: &ExecutionContext) -> Result<()> {
let uv_exec = require("uv")?;
print_separator("uv");
// try uv self --help first - if it succeeds, we call uv self update
let result = ctx
.run_type()
.execute(&uv_exec)
.args(["self", "--help"])
.output_checked();
if result.is_ok() {
ctx.run_type()
.execute(&uv_exec)
.args(["self", "update"])
.status_checked()
.ok();
// ignoring self-update errors, because they are likely due to uv's
// installation being managed by another package manager, in which
// case another step will handle the update.
}
ctx.run_type()
.execute(&uv_exec)

View File

@@ -184,6 +184,92 @@ impl Yarn {
}
}
struct Deno {
command: PathBuf,
}
impl Deno {
fn new(command: PathBuf) -> Self {
Self { command }
}
fn upgrade(&self, ctx: &ExecutionContext) -> Result<()> {
let mut args = vec![];
let version = ctx.config().deno_version();
if let Some(version) = version {
let bin_version = self.version()?;
if bin_version >= Version::new(2, 0, 0) {
args.push(version);
} else if bin_version >= Version::new(1, 6, 0) {
match version {
"stable" => { /* do nothing, as stable is the default channel to upgrade */ }
"rc" => {
return Err(SkipStep(
"Deno (1.6.0-2.0.0) cannot be upgraded to a release candidate".to_string(),
)
.into());
}
"canary" => args.push("--canary"),
_ => {
if Version::parse(version).is_err() {
return Err(SkipStep("Invalid Deno version".to_string()).into());
}
args.push("--version");
args.push(version);
}
}
} else if bin_version >= Version::new(1, 0, 0) {
match version {
"stable" | "rc" | "canary" => {
// Prior to v1.6.0, `deno upgrade` is not able fetch the latest tag version.
return Err(
SkipStep("Deno (1.0.0-1.6.0) cannot be upgraded to a named channel".to_string()).into(),
);
}
_ => {
if Version::parse(version).is_err() {
return Err(SkipStep("Invalid Deno version".to_string()).into());
}
args.push("--version");
args.push(version);
}
}
} else {
// v0.x cannot be upgraded with `deno upgrade` to v1.x or v2.x
// nor can be upgraded to a specific version.
return Err(SkipStep("Unsupported Deno version".to_string()).into());
}
}
ctx.run_type()
.execute(&self.command)
.arg("upgrade")
.args(args)
.status_checked()?;
Ok(())
}
/// Get the version of Deno.
///
/// This function will return the version of Deno installed on the system.
/// The version is parsed from the output of `deno -V`.
///
/// ```sh
/// deno -V # deno 1.6.0
/// ```
fn version(&self) -> Result<Version> {
let version_str = Command::new(&self.command)
.args(["-V"])
.output_checked_utf8()
.map(|s| s.stdout.trim().to_owned().split_off(5)); // remove "deno " prefix
Version::parse(&version_str?).map_err(|err| err.into())
}
}
#[cfg(target_os = "linux")]
fn should_use_sudo(npm: &NPM, ctx: &ExecutionContext) -> Result<bool> {
if npm.should_use_sudo()? {
@@ -266,16 +352,16 @@ pub fn run_yarn_upgrade(ctx: &ExecutionContext) -> Result<()> {
}
pub fn deno_upgrade(ctx: &ExecutionContext) -> Result<()> {
let deno = require("deno")?;
let deno = require("deno").map(Deno::new)?;
let deno_dir = HOME_DIR.join(".deno");
if !deno.canonicalize()?.is_descendant_of(&deno_dir) {
if !deno.command.canonicalize()?.is_descendant_of(&deno_dir) {
let skip_reason = SkipStep(t!("Deno installed outside of .deno directory").to_string());
return Err(skip_reason.into());
}
print_separator("Deno");
ctx.run_type().execute(&deno).arg("upgrade").status_checked()
deno.upgrade(ctx)
}
/// There is no `volta upgrade` command, so we need to upgrade each package

View File

@@ -225,7 +225,12 @@ fn upgrade_wolfi_linux(ctx: &ExecutionContext) -> Result<()> {
}
fn upgrade_redhat(ctx: &ExecutionContext) -> Result<()> {
if let Some(ostree) = which("rpm-ostree") {
if let Some(bootc) = which("bootc") {
if ctx.config().bootc() {
let sudo = require_option(ctx.sudo().as_ref(), get_require_sudo_string())?;
return ctx.run_type().execute(sudo).arg(&bootc).arg("upgrade").status_checked();
}
} else if let Some(ostree) = which("rpm-ostree") {
if ctx.config().rpm_ostree() {
let mut command = ctx.run_type().execute(ostree);
command.arg("upgrade");
@@ -298,6 +303,13 @@ fn upgrade_nilrt(ctx: &ExecutionContext) -> Result<()> {
}
fn upgrade_fedora_immutable(ctx: &ExecutionContext) -> Result<()> {
if let Some(bootc) = which("bootc") {
if ctx.config().bootc() {
let sudo = require_option(ctx.sudo().as_ref(), get_require_sudo_string())?;
return ctx.run_type().execute(sudo).arg(&bootc).arg("upgrade").status_checked();
}
}
let ostree = require("rpm-ostree")?;
let mut command = ctx.run_type().execute(ostree);
command.arg("upgrade");

View File

@@ -3,20 +3,50 @@ use crate::execution_context::ExecutionContext;
use crate::terminal::print_separator;
use crate::utils::{get_require_sudo_string, require_option};
use color_eyre::eyre::Result;
use rust_i18n::t;
use std::fs;
fn is_openbsd_current(ctx: &ExecutionContext) -> Result<bool> {
let motd_content = fs::read_to_string("/etc/motd")?;
let is_current = motd_content.contains("-current");
if ctx.config().dry_run() {
println!("{}", t!("Would check if OpenBSD is -current"));
Ok(is_current)
} else {
Ok(is_current)
}
}
pub fn upgrade_openbsd(ctx: &ExecutionContext) -> Result<()> {
let sudo = require_option(ctx.sudo().as_ref(), get_require_sudo_string())?;
print_separator(t!("OpenBSD Update"));
ctx.run_type()
.execute(sudo)
.args(["/usr/sbin/sysupgrade", "-n"])
.status_checked()
let is_current = is_openbsd_current(ctx)?;
if ctx.config().dry_run() {
println!("{}", t!("Would upgrade the OpenBSD system"));
return Ok(());
}
let mut args = vec!["/usr/sbin/sysupgrade", "-n"];
if is_current {
args.push("-s");
}
ctx.run_type().execute(sudo).args(&args).status_checked()
}
pub fn upgrade_packages(ctx: &ExecutionContext) -> Result<()> {
let sudo = require_option(ctx.sudo().as_ref(), get_require_sudo_string())?;
print_separator(t!("OpenBSD Packages"));
let is_current = is_openbsd_current(ctx)?;
if ctx.config().dry_run() {
println!("{}", t!("Would upgrade OpenBSD packages"));
return Ok(());
}
if ctx.config().cleanup() {
ctx.run_type()
.execute(sudo)
@@ -24,10 +54,12 @@ pub fn upgrade_packages(ctx: &ExecutionContext) -> Result<()> {
.status_checked()?;
}
ctx.run_type()
.execute(sudo)
.args(["/usr/sbin/pkg_add", "-u"])
.status_checked()?;
let mut args = vec!["/usr/sbin/pkg_add", "-u"];
if is_current {
args.push("-Dsnap");
}
ctx.run_type().execute(sudo).args(&args).status_checked()?;
Ok(())
}

View File

@@ -13,8 +13,10 @@ use color_eyre::eyre::Context;
use color_eyre::eyre::Result;
use home;
use ini::Ini;
use lazy_static::lazy_static;
#[cfg(target_os = "linux")]
use nix::unistd::Uid;
use regex::Regex;
use rust_i18n::t;
use semver::Version;
use tracing::debug;
@@ -449,18 +451,44 @@ pub fn run_nix(ctx: &ExecutionContext) -> Result<()> {
.stdout
.lines()
.next()
.expect("nix --version gives an empty output");
let splitted: Vec<&str> = get_version_cmd_first_line_stdout.split_whitespace().collect();
let version = if splitted.len() >= 3 {
Version::parse(splitted[2]).expect("invalid version")
} else {
panic!("nix --version output format changed, file an issue to Topgrade!")
.ok_or_else(|| eyre!("`nix --version` output is empty"))?;
let is_lix = get_version_cmd_first_line_stdout.contains("Lix");
debug!(
output=%get_version_cmd_output,
?is_lix,
"`nix --version` output"
);
lazy_static! {
static ref NIX_VERSION_REGEX: Regex =
Regex::new(r#"^nix \([^)]*\) ([0-9.]+)"#).expect("Nix version regex always compiles");
}
if get_version_cmd_first_line_stdout.is_empty() {
return Err(eyre!("`nix --version` output was empty"));
}
let captures = NIX_VERSION_REGEX.captures(get_version_cmd_first_line_stdout);
let raw_version = match &captures {
None => {
return Err(eyre!(
"`nix --version` output was weird: {get_version_cmd_first_line_stdout:?}\n\
If the `nix --version` output format changed, please file an issue to Topgrade"
));
}
Some(captures) => &captures[1],
};
let version =
Version::parse(raw_version).wrap_err_with(|| format!("Unable to parse Nix version: {raw_version:?}"))?;
debug!("Nix version: {:?}", version);
// Nix since 2.21.0 uses `--all --impure` rather than `.*` to upgrade all packages
let packages = if version >= Version::new(2, 21, 0) {
// Nix since 2.21.0 uses `--all --impure` rather than `.*` to upgrade all packages.
// Lix is based on Nix 2.18, so it doesn't!
let packages = if version >= Version::new(2, 21, 0) && !is_lix {
vec!["--all", "--impure"]
} else {
vec![".*"]
@@ -625,12 +653,12 @@ pub fn run_mise(ctx: &ExecutionContext) -> Result<()> {
print_separator("mise");
ctx.run_type().execute(&mise).arg("upgrade").status_checked()?;
ctx.run_type()
.execute(&mise)
.args(["plugins", "update"])
.status_checked()
.status_checked()?;
ctx.run_type().execute(&mise).arg("upgrade").status_checked()
}
pub fn run_home_manager(ctx: &ExecutionContext) -> Result<()> {

View File

@@ -221,6 +221,14 @@ pub fn windows_update(ctx: &ExecutionContext) -> Result<()> {
}
}
pub fn microsoft_store(ctx: &ExecutionContext) -> Result<()> {
let powershell = powershell::Powershell::windows_powershell();
print_separator(t!("Microsoft Store"));
powershell.microsoft_store(ctx)
}
pub fn reboot() -> Result<()> {
// If this works, it won't return, but if it doesn't work, it may return a useful error
// message.

View File

@@ -119,4 +119,43 @@ impl Powershell {
.args(["-NoProfile", &install_windowsupdate_verbose, accept_all])
.status_checked()
}
#[cfg(windows)]
pub fn microsoft_store(&self, ctx: &ExecutionContext) -> Result<()> {
let powershell = require_option(self.path.as_ref(), t!("Powershell is not installed").to_string())?;
let mut command = if let Some(sudo) = ctx.sudo() {
let mut command = ctx.run_type().execute(sudo);
command.arg(powershell);
command
} else {
ctx.run_type().execute(powershell)
};
println!("{}", t!("Scanning for updates..."));
// Scan for updates using the MDM UpdateScanMethod
// This method is also available for non-MDM devices
let update_command = "(Get-CimInstance -Namespace \"Root\\cimv2\\mdm\\dmmap\" -ClassName \"MDM_EnterpriseModernAppManagement_AppManagement01\" | Invoke-CimMethod -MethodName UpdateScanMethod).ReturnValue";
command.args(["-NoProfile", update_command]);
command
.output_checked_with_utf8(|output| {
if output.stdout.trim() == "0" {
println!(
"{}",
t!("Success, Microsoft Store apps are being updated in the background")
);
Ok(())
} else {
println!(
"{}",
t!("Unable to update Microsoft Store apps, manual intervention is required")
);
Err(())
}
})
.map(|_| ())
}
}

View File

@@ -126,7 +126,7 @@ impl<'a> TemporaryPowerOn<'a> {
}
}
impl<'a> Drop for TemporaryPowerOn<'a> {
impl Drop for TemporaryPowerOn<'_> {
fn drop(&mut self) {
let subcommand = if self.ctx.config().vagrant_always_suspend().unwrap_or(false) {
"suspend"