Compare commits
54 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
4488f3d5d3 | ||
|
|
5a7958d20e | ||
|
|
481a942b76 | ||
|
|
a601d8429d | ||
|
|
a4a2d52a6d | ||
|
|
47fa3ba7de | ||
|
|
e6bb6709b3 | ||
|
|
c421742c4f | ||
|
|
1312cc8f6e | ||
|
|
ed37763d30 | ||
|
|
583bbf65e2 | ||
|
|
5770a5caa7 | ||
|
|
722903fec3 | ||
|
|
30f1c3c1b4 | ||
|
|
ef7d146282 | ||
|
|
20667a23d3 | ||
|
|
26f05827ae | ||
|
|
b1ffe7d553 | ||
|
|
368a060529 | ||
|
|
b40bffb1f2 | ||
|
|
488ae149f7 | ||
|
|
fa3e4726b7 | ||
|
|
66a12cc8bf | ||
|
|
3e0c21e981 | ||
|
|
da270ae7d9 | ||
|
|
4624f11ba5 | ||
|
|
224bb96a98 | ||
|
|
9a6fe8eea9 | ||
|
|
aebc035ec0 | ||
|
|
bd348c328e | ||
|
|
c5f2d7b473 | ||
|
|
dc9d8d55f2 | ||
|
|
b172ba7f03 | ||
|
|
8227890808 | ||
|
|
a0963fe3fc | ||
|
|
4df30c2587 | ||
|
|
305a5fbcae | ||
|
|
4f4dcbb643 | ||
|
|
202897ba35 | ||
|
|
444689c899 | ||
|
|
98ec13f8db | ||
|
|
39f76a3a71 | ||
|
|
f181a795a6 | ||
|
|
ea2f3e07e9 | ||
|
|
8aad6eae0d | ||
|
|
e86e5fe3e7 | ||
|
|
2c2569c4f8 | ||
|
|
9ffdc9649e | ||
|
|
a5d4f2eec9 | ||
|
|
a5df40e01d | ||
|
|
0573fc97c6 | ||
|
|
1ae95f41a1 | ||
|
|
8a7af2e14d | ||
|
|
c36da89933 |
3
.github/PULL_REQUEST_TEMPLATE.md
vendored
3
.github/PULL_REQUEST_TEMPLATE.md
vendored
@@ -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
|
||||
|
||||
|
||||
@@ -6,20 +6,21 @@ on:
|
||||
# types:
|
||||
# - completed
|
||||
release:
|
||||
types: [ created ]
|
||||
types: [created]
|
||||
|
||||
jobs:
|
||||
build:
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
target: [
|
||||
"aarch64-unknown-linux-gnu",
|
||||
"armv7-unknown-linux-gnueabihf",
|
||||
"x86_64-unknown-linux-musl",
|
||||
"aarch64-unknown-linux-musl",
|
||||
"x86_64-unknown-freebsd",
|
||||
]
|
||||
target:
|
||||
[
|
||||
"aarch64-unknown-linux-gnu",
|
||||
"armv7-unknown-linux-gnueabihf",
|
||||
"x86_64-unknown-linux-musl",
|
||||
"aarch64-unknown-linux-musl",
|
||||
"x86_64-unknown-freebsd",
|
||||
]
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
@@ -29,9 +30,14 @@ jobs:
|
||||
if: ${{ matrix.target == 'aarch64-unknown-linux-gnu' }}
|
||||
shell: bash
|
||||
|
||||
- name: Install cargo-deb cross compilation dependencies for armv7
|
||||
run: sudo apt-get install libc6-armhf-cross libgcc-s1-armhf-cross
|
||||
if: ${{ matrix.target == 'armv7-unknown-linux-gnueabihf' }}
|
||||
shell: bash
|
||||
|
||||
- name: Install cargo-deb
|
||||
run: cargo install cargo-deb
|
||||
if: ${{ matrix.target == 'aarch64-unknown-linux-gnu' }}
|
||||
if: ${{ matrix.target == 'aarch64-unknown-linux-gnu' || matrix.target == 'armv7-unknown-linux-gnueabihf' }}
|
||||
shell: bash
|
||||
|
||||
- name: install targets
|
||||
@@ -75,14 +81,14 @@ jobs:
|
||||
rm -rf target/${{matrix.target}}
|
||||
cross build --release --target ${{matrix.target}}
|
||||
cargo deb --target=${{matrix.target}} --no-build --no-strip
|
||||
if: ${{ matrix.target == 'aarch64-unknown-linux-gnu' }}
|
||||
if: ${{ matrix.target == 'aarch64-unknown-linux-gnu' || matrix.target == 'armv7-unknown-linux-gnueabihf' }}
|
||||
shell: bash
|
||||
|
||||
- name: Move Debian-based system package
|
||||
run: |
|
||||
mkdir -p assets
|
||||
mv target/${{matrix.target}}/debian/*.deb assets
|
||||
if: ${{ matrix.target == 'aarch64-unknown-linux-gnu' }}
|
||||
if: ${{ matrix.target == 'aarch64-unknown-linux-gnu' || matrix.target == 'armv7-unknown-linux-gnueabihf' }}
|
||||
shell: bash
|
||||
|
||||
- name: Release
|
||||
|
||||
10
.github/workflows/release_to_aur.yml
vendored
10
.github/workflows/release_to_aur.yml
vendored
@@ -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 }}
|
||||
|
||||
@@ -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".
|
||||
|
||||
@@ -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
|
||||
|
||||
300
Cargo.lock
generated
300
Cargo.lock
generated
@@ -1,6 +1,6 @@
|
||||
# This file is automatically @generated by Cargo.
|
||||
# It is not intended for manual editing.
|
||||
version = 3
|
||||
version = 4
|
||||
|
||||
[[package]]
|
||||
name = "addr2line"
|
||||
@@ -202,7 +202,7 @@ checksum = "3b43422f69d8ff38f95f1b2bb76517c91589a924d1559a0e935d7c8ce0274c11"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.66",
|
||||
"syn 2.0.99",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -237,7 +237,7 @@ checksum = "c6fa2087f2753a7da8cc1c0dbfcf89579dd57458e36769de5ac750b4671737ca"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.66",
|
||||
"syn 2.0.99",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -355,9 +355,12 @@ checksum = "514de17de45fdb8dc022b1a7975556c53c86f9f0aa5f534b98977b171857c2c9"
|
||||
|
||||
[[package]]
|
||||
name = "cc"
|
||||
version = "1.0.99"
|
||||
version = "1.2.16"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "96c51067fd44124faa7f870b4b1c969379ad32b2ba805aa959430ceaa384f695"
|
||||
checksum = "be714c154be609ec7f5dad223a33bf1482fff90472de28f7362806e6d4832b8c"
|
||||
dependencies = [
|
||||
"shlex",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "cfg-if"
|
||||
@@ -388,7 +391,7 @@ dependencies = [
|
||||
"js-sys",
|
||||
"num-traits",
|
||||
"wasm-bindgen",
|
||||
"windows-targets 0.52.5",
|
||||
"windows-targets 0.52.6",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -431,7 +434,7 @@ dependencies = [
|
||||
"heck",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.66",
|
||||
"syn 2.0.99",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -533,9 +536,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "core-foundation-sys"
|
||||
version = "0.8.6"
|
||||
version = "0.8.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "06ea2b9bc92be3c2baa9334a323ebca2d6f074ff852cd1d7b11064035cd3868f"
|
||||
checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b"
|
||||
|
||||
[[package]]
|
||||
name = "cpufeatures"
|
||||
@@ -620,7 +623,7 @@ checksum = "f46882e17999c6cc590af592290432be3bce0428cb0d5f8b6715e4dc7b383eb3"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.66",
|
||||
"syn 2.0.99",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -658,7 +661,16 @@ version = "5.0.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "44c45a9d03d6676652bcb5e724c7e988de1acad23a711b5217ab9cbecbec2225"
|
||||
dependencies = [
|
||||
"dirs-sys",
|
||||
"dirs-sys 0.4.1",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "dirs"
|
||||
version = "6.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c3e8aa94d75141228480295a7d0e7feb620b1a5ad9f12bc40be62411e38cce4e"
|
||||
dependencies = [
|
||||
"dirs-sys 0.5.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -679,10 +691,22 @@ checksum = "520f05a5cbd335fae5a99ff7a6ab8627577660ee5cfd6a94a6a929b52ff0321c"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"option-ext",
|
||||
"redox_users",
|
||||
"redox_users 0.4.5",
|
||||
"windows-sys 0.48.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "dirs-sys"
|
||||
version = "0.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e01a3366d27ee9890022452ee61b2b63a67e6f13f58900b651ff5665f0bb1fab"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"option-ext",
|
||||
"redox_users 0.5.0",
|
||||
"windows-sys 0.59.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "dirs-sys-next"
|
||||
version = "0.1.2"
|
||||
@@ -690,7 +714,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4ebda144c4fe02d1f7ea1a7d9641b6fc6b580adcfa024ae48797ecdeb6825b4d"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"redox_users",
|
||||
"redox_users 0.4.5",
|
||||
"winapi",
|
||||
]
|
||||
|
||||
@@ -702,7 +726,7 @@ checksum = "487585f4d0c6655fe74905e2504d8ad6908e4db67f744eb140876906c2f3175d"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.66",
|
||||
"syn 2.0.99",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -775,7 +799,7 @@ checksum = "de0d48a183585823424a4ce1aa132d174a6a81bd540895822eb4c8373a8e49e8"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.66",
|
||||
"syn 2.0.99",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -963,7 +987,7 @@ checksum = "87750cf4b7a4c0625b1529e4c543c2182106e4dedc60a2a6455e00d212c489ac"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.66",
|
||||
"syn 2.0.99",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -1326,7 +1350,7 @@ checksum = "1ec89e9337638ecdc08744df490b221a7399bf8d164eb52a665454e60e075ad6"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.66",
|
||||
"syn 2.0.99",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -1423,6 +1447,17 @@ version = "1.0.11"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "49f1f14873335454500d59611f1cf4a4b0f786f9ac11f4312a78e4cf2566695b"
|
||||
|
||||
[[package]]
|
||||
name = "jetbrains-toolbox-updater"
|
||||
version = "1.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b9d86b38fee698b3f63c9772fe2832d03a84e0724e409d499517c8a102949717"
|
||||
dependencies = [
|
||||
"dirs 6.0.0",
|
||||
"json",
|
||||
"sysinfo",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "js-sys"
|
||||
version = "0.3.69"
|
||||
@@ -1432,6 +1467,12 @@ dependencies = [
|
||||
"wasm-bindgen",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "json"
|
||||
version = "0.12.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "078e285eafdfb6c4b434e0d31e8cfcb5115b651496faca5749b88fafd4f23bfd"
|
||||
|
||||
[[package]]
|
||||
name = "lazy_static"
|
||||
version = "1.4.0"
|
||||
@@ -1440,9 +1481,9 @@ checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
|
||||
|
||||
[[package]]
|
||||
name = "libc"
|
||||
version = "0.2.155"
|
||||
version = "0.2.170"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "97b3888a4aecf77e811145cadf6eef5901f4782c53886191b2f693f24761847c"
|
||||
checksum = "875b3680cb2f8f71bdcf9a30f38d48282f5d3c95cbf9b3fa57269bb5d5c06828"
|
||||
|
||||
[[package]]
|
||||
name = "libredox"
|
||||
@@ -1619,6 +1660,15 @@ dependencies = [
|
||||
"zbus",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ntapi"
|
||||
version = "0.4.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e8a3895c6391c39d7fe7ebc444a87eb2991b2a0bc718fdabd071eec617fc68e4"
|
||||
dependencies = [
|
||||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "nu-ansi-term"
|
||||
version = "0.46.0"
|
||||
@@ -1757,7 +1807,7 @@ dependencies = [
|
||||
"bitflags 1.3.2",
|
||||
"byteorder",
|
||||
"chrono",
|
||||
"thiserror",
|
||||
"thiserror 1.0.61",
|
||||
"widestring",
|
||||
]
|
||||
|
||||
@@ -1784,7 +1834,7 @@ checksum = "2f38a4412a78282e09a2cf38d195ea5420d15ba0602cb375210efbc877243965"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.66",
|
||||
"syn 2.0.99",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -1888,9 +1938,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "proc-macro2"
|
||||
version = "1.0.85"
|
||||
version = "1.0.94"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "22244ce15aa966053a896d1accb3a6e68469b97c7f33f284b99f0d576879fc23"
|
||||
checksum = "a31971752e70b8b2686d7e46ec17fb38dad4051d94024c88df49b667caea9c84"
|
||||
dependencies = [
|
||||
"unicode-ident",
|
||||
]
|
||||
@@ -1952,6 +2002,26 @@ dependencies = [
|
||||
"getrandom",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rayon"
|
||||
version = "1.10.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b418a60154510ca1a002a752ca9714984e21e4241e804d32555251faf8b78ffa"
|
||||
dependencies = [
|
||||
"either",
|
||||
"rayon-core",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rayon-core"
|
||||
version = "1.12.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1465873a3dfdaa8ae7cb14b4383657caab0b3e8a0aa9ae8e04b044854c8dfce2"
|
||||
dependencies = [
|
||||
"crossbeam-deque",
|
||||
"crossbeam-utils",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "redox_syscall"
|
||||
version = "0.4.1"
|
||||
@@ -1969,7 +2039,18 @@ checksum = "bd283d9651eeda4b2a83a43c1c91b266c40fd76ecd39a50a8c630ae69dc72891"
|
||||
dependencies = [
|
||||
"getrandom",
|
||||
"libredox",
|
||||
"thiserror",
|
||||
"thiserror 1.0.61",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "redox_users"
|
||||
version = "0.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "dd6f9d3d47bdd2ad6945c5015a226ec6155d0bcdfd8f7cd29f86b71f8de99d2b"
|
||||
dependencies = [
|
||||
"getrandom",
|
||||
"libredox",
|
||||
"thiserror 2.0.12",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -2069,15 +2150,14 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "ring"
|
||||
version = "0.17.8"
|
||||
version = "0.17.13"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c17fa4cb658e3583423e915b9f3acc01cceaee1860e33d59ebae66adc3a2dc0d"
|
||||
checksum = "70ac5d832aa16abd7d1def883a8545280c20a60f523a370aa3a9617c2b8550ee"
|
||||
dependencies = [
|
||||
"cc",
|
||||
"cfg-if",
|
||||
"getrandom",
|
||||
"libc",
|
||||
"spin",
|
||||
"untrusted",
|
||||
"windows-sys 0.52.0",
|
||||
]
|
||||
@@ -2116,7 +2196,7 @@ dependencies = [
|
||||
"serde",
|
||||
"serde_json",
|
||||
"serde_yaml",
|
||||
"syn 2.0.66",
|
||||
"syn 2.0.99",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -2298,7 +2378,7 @@ checksum = "500cbc0ebeb6f46627f50f3f5811ccf6bf00643be300b4c3eabc0ef55dc5b5ba"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.66",
|
||||
"syn 2.0.99",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -2320,7 +2400,7 @@ checksum = "6c64451ba24fc7a6a2d60fc75dd9c83c90903b19028d4eff35e88fc1e86564e9"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.66",
|
||||
"syn 2.0.99",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -2399,9 +2479,15 @@ version = "3.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "da03fa3b94cc19e3ebfc88c4229c49d8f08cdbd1228870a45f0ffdf84988e14b"
|
||||
dependencies = [
|
||||
"dirs",
|
||||
"dirs 5.0.1",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "shlex"
|
||||
version = "1.3.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64"
|
||||
|
||||
[[package]]
|
||||
name = "signal-hook-registry"
|
||||
version = "1.4.2"
|
||||
@@ -2446,12 +2532,6 @@ dependencies = [
|
||||
"windows-sys 0.52.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "spin"
|
||||
version = "0.9.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6980e8d7511241f8acf4aebddbb1ff938df5eebe98691418c4468d0b72a96a67"
|
||||
|
||||
[[package]]
|
||||
name = "spki"
|
||||
version = "0.7.3"
|
||||
@@ -2499,7 +2579,7 @@ dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"rustversion",
|
||||
"syn 2.0.66",
|
||||
"syn 2.0.99",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -2521,9 +2601,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "syn"
|
||||
version = "2.0.66"
|
||||
version = "2.0.99"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c42f3f41a2de00b01c0aaad383c5a45241efc8b2d1eda5661812fda5f3cdcff5"
|
||||
checksum = "e02e925281e18ffd9d640e234264753c43edc62d64b2d4cf898f1bc5e75f3fc2"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
@@ -2544,7 +2624,7 @@ checksum = "c8af7666ab7b6390ab78131fb5b0fce11d6b7a6951602017c35fa82800708971"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.66",
|
||||
"syn 2.0.99",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -2556,6 +2636,20 @@ dependencies = [
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "sysinfo"
|
||||
version = "0.33.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4fc858248ea01b66f19d8e8a6d55f41deaf91e9d495246fd01368d99935c6c01"
|
||||
dependencies = [
|
||||
"core-foundation-sys",
|
||||
"libc",
|
||||
"memchr",
|
||||
"ntapi",
|
||||
"rayon",
|
||||
"windows",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tar"
|
||||
version = "0.4.41"
|
||||
@@ -2596,7 +2690,16 @@ version = "1.0.61"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c546c80d6be4bc6a00c0f01730c08df82eaa7a7a61f11d656526506112cc1709"
|
||||
dependencies = [
|
||||
"thiserror-impl",
|
||||
"thiserror-impl 1.0.61",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "thiserror"
|
||||
version = "2.0.12"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "567b8a2dae586314f7be2a752ec7474332959c6460e02bde30d702a66d488708"
|
||||
dependencies = [
|
||||
"thiserror-impl 2.0.12",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -2607,7 +2710,18 @@ checksum = "46c3384250002a6d5af4d114f2845d37b57521033f30d5c3f46c4d70e1197533"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.66",
|
||||
"syn 2.0.99",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "thiserror-impl"
|
||||
version = "2.0.12"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7f7cf42b4507d8ea322120659672cf1b9dbb93f8f2d4ecfd6e51350ff5b17a1d"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.99",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -2770,7 +2884,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "topgrade"
|
||||
version = "16.0.1"
|
||||
version = "16.0.3"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"chrono",
|
||||
@@ -2783,6 +2897,7 @@ dependencies = [
|
||||
"futures",
|
||||
"glob",
|
||||
"home",
|
||||
"jetbrains-toolbox-updater",
|
||||
"lazy_static",
|
||||
"merge",
|
||||
"nix 0.29.0",
|
||||
@@ -2801,7 +2916,7 @@ dependencies = [
|
||||
"strum",
|
||||
"sys-locale",
|
||||
"tempfile",
|
||||
"thiserror",
|
||||
"thiserror 1.0.61",
|
||||
"tokio",
|
||||
"toml 0.8.14",
|
||||
"tracing",
|
||||
@@ -2859,7 +2974,7 @@ checksum = "34704c8d6ebcbc939824180af020566b01a7c01f80641264eba0999f6c2b6be7"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.66",
|
||||
"syn 2.0.99",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -3063,7 +3178,7 @@ dependencies = [
|
||||
"once_cell",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.66",
|
||||
"syn 2.0.99",
|
||||
"wasm-bindgen-shared",
|
||||
]
|
||||
|
||||
@@ -3097,7 +3212,7 @@ checksum = "e94f17b526d0a461a191c78ea52bbce64071ed5c04c9ffe424dcb38f74171bb7"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.66",
|
||||
"syn 2.0.99",
|
||||
"wasm-bindgen-backend",
|
||||
"wasm-bindgen-shared",
|
||||
]
|
||||
@@ -3189,7 +3304,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1de69df01bdf1ead2f4ac895dc77c9351aefff65b2f3db429a343f9cbf05e132"
|
||||
dependencies = [
|
||||
"windows-core 0.56.0",
|
||||
"windows-targets 0.52.5",
|
||||
"windows-targets 0.52.6",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -3198,7 +3313,7 @@ version = "0.52.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "33ab640c8d7e35bf8ba19b884ba838ceb4fba93a4e8c65a9059d08afcfc683d9"
|
||||
dependencies = [
|
||||
"windows-targets 0.52.5",
|
||||
"windows-targets 0.52.6",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -3210,7 +3325,7 @@ dependencies = [
|
||||
"windows-implement",
|
||||
"windows-interface",
|
||||
"windows-result",
|
||||
"windows-targets 0.52.5",
|
||||
"windows-targets 0.52.6",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -3221,7 +3336,7 @@ checksum = "f6fc35f58ecd95a9b71c4f2329b911016e6bec66b3f2e6a4aad86bd2e99e2f9b"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.66",
|
||||
"syn 2.0.99",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -3232,7 +3347,7 @@ checksum = "08990546bf4edef8f431fa6326e032865f27138718c587dc21bc0265bbcb57cc"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.66",
|
||||
"syn 2.0.99",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -3241,7 +3356,7 @@ version = "0.1.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5e383302e8ec8515204254685643de10811af0ed97ea37210dc26fb0032647f8"
|
||||
dependencies = [
|
||||
"windows-targets 0.52.5",
|
||||
"windows-targets 0.52.6",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -3259,7 +3374,16 @@ version = "0.52.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d"
|
||||
dependencies = [
|
||||
"windows-targets 0.52.5",
|
||||
"windows-targets 0.52.6",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows-sys"
|
||||
version = "0.59.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b"
|
||||
dependencies = [
|
||||
"windows-targets 0.52.6",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -3279,18 +3403,18 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "windows-targets"
|
||||
version = "0.52.5"
|
||||
version = "0.52.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6f0713a46559409d202e70e28227288446bf7841d3211583a4b53e3f6d96e7eb"
|
||||
checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973"
|
||||
dependencies = [
|
||||
"windows_aarch64_gnullvm 0.52.5",
|
||||
"windows_aarch64_msvc 0.52.5",
|
||||
"windows_i686_gnu 0.52.5",
|
||||
"windows_aarch64_gnullvm 0.52.6",
|
||||
"windows_aarch64_msvc 0.52.6",
|
||||
"windows_i686_gnu 0.52.6",
|
||||
"windows_i686_gnullvm",
|
||||
"windows_i686_msvc 0.52.5",
|
||||
"windows_x86_64_gnu 0.52.5",
|
||||
"windows_x86_64_gnullvm 0.52.5",
|
||||
"windows_x86_64_msvc 0.52.5",
|
||||
"windows_i686_msvc 0.52.6",
|
||||
"windows_x86_64_gnu 0.52.6",
|
||||
"windows_x86_64_gnullvm 0.52.6",
|
||||
"windows_x86_64_msvc 0.52.6",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -3299,7 +3423,7 @@ version = "0.1.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6998aa457c9ba8ff2fb9f13e9d2a930dabcea28f1d0ab94d687d8b3654844515"
|
||||
dependencies = [
|
||||
"windows-targets 0.52.5",
|
||||
"windows-targets 0.52.6",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -3310,9 +3434,9 @@ checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8"
|
||||
|
||||
[[package]]
|
||||
name = "windows_aarch64_gnullvm"
|
||||
version = "0.52.5"
|
||||
version = "0.52.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7088eed71e8b8dda258ecc8bac5fb1153c5cffaf2578fc8ff5d61e23578d3263"
|
||||
checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3"
|
||||
|
||||
[[package]]
|
||||
name = "windows_aarch64_msvc"
|
||||
@@ -3322,9 +3446,9 @@ checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc"
|
||||
|
||||
[[package]]
|
||||
name = "windows_aarch64_msvc"
|
||||
version = "0.52.5"
|
||||
version = "0.52.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9985fd1504e250c615ca5f281c3f7a6da76213ebd5ccc9561496568a2752afb6"
|
||||
checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469"
|
||||
|
||||
[[package]]
|
||||
name = "windows_i686_gnu"
|
||||
@@ -3334,15 +3458,15 @@ checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e"
|
||||
|
||||
[[package]]
|
||||
name = "windows_i686_gnu"
|
||||
version = "0.52.5"
|
||||
version = "0.52.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "88ba073cf16d5372720ec942a8ccbf61626074c6d4dd2e745299726ce8b89670"
|
||||
checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b"
|
||||
|
||||
[[package]]
|
||||
name = "windows_i686_gnullvm"
|
||||
version = "0.52.5"
|
||||
version = "0.52.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "87f4261229030a858f36b459e748ae97545d6f1ec60e5e0d6a3d32e0dc232ee9"
|
||||
checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66"
|
||||
|
||||
[[package]]
|
||||
name = "windows_i686_msvc"
|
||||
@@ -3352,9 +3476,9 @@ checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406"
|
||||
|
||||
[[package]]
|
||||
name = "windows_i686_msvc"
|
||||
version = "0.52.5"
|
||||
version = "0.52.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "db3c2bf3d13d5b658be73463284eaf12830ac9a26a90c717b7f771dfe97487bf"
|
||||
checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66"
|
||||
|
||||
[[package]]
|
||||
name = "windows_x86_64_gnu"
|
||||
@@ -3364,9 +3488,9 @@ checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e"
|
||||
|
||||
[[package]]
|
||||
name = "windows_x86_64_gnu"
|
||||
version = "0.52.5"
|
||||
version = "0.52.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4e4246f76bdeff09eb48875a0fd3e2af6aada79d409d33011886d3e1581517d9"
|
||||
checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78"
|
||||
|
||||
[[package]]
|
||||
name = "windows_x86_64_gnullvm"
|
||||
@@ -3376,9 +3500,9 @@ checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc"
|
||||
|
||||
[[package]]
|
||||
name = "windows_x86_64_gnullvm"
|
||||
version = "0.52.5"
|
||||
version = "0.52.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "852298e482cd67c356ddd9570386e2862b5673c85bd5f88df9ab6802b334c596"
|
||||
checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d"
|
||||
|
||||
[[package]]
|
||||
name = "windows_x86_64_msvc"
|
||||
@@ -3388,9 +3512,9 @@ checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538"
|
||||
|
||||
[[package]]
|
||||
name = "windows_x86_64_msvc"
|
||||
version = "0.52.5"
|
||||
version = "0.52.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bec47e5bfd1bff0eeaf6d8b485cc1074891a197ab4225d504cb7a1ab88b02bf0"
|
||||
checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec"
|
||||
|
||||
[[package]]
|
||||
name = "winnow"
|
||||
@@ -3488,7 +3612,7 @@ checksum = "28cc31741b18cb6f1d5ff12f5b7523e3d6eb0852bbbad19d73905511d9849b95"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.66",
|
||||
"syn 2.0.99",
|
||||
"synstructure",
|
||||
]
|
||||
|
||||
@@ -3539,7 +3663,7 @@ dependencies = [
|
||||
"proc-macro-crate",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.66",
|
||||
"syn 2.0.99",
|
||||
"zvariant_utils",
|
||||
]
|
||||
|
||||
@@ -3571,7 +3695,7 @@ checksum = "0ea7b4a3637ea8669cedf0f1fd5c286a17f3de97b8dd5a70a6c167a1730e63a5"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.66",
|
||||
"syn 2.0.99",
|
||||
"synstructure",
|
||||
]
|
||||
|
||||
@@ -3600,7 +3724,7 @@ checksum = "6eafa6dfb17584ea3e2bd6e76e0cc15ad7af12b09abdd1ca55961bed9b1063c6"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.66",
|
||||
"syn 2.0.99",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -3624,7 +3748,7 @@ checksum = "2ba5aa1827d6b1a35a29b3413ec69ce5f796e4d897e3e5b38f461bef41d225ea"
|
||||
dependencies = [
|
||||
"base64 0.21.7",
|
||||
"ed25519-dalek",
|
||||
"thiserror",
|
||||
"thiserror 1.0.61",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -3649,7 +3773,7 @@ dependencies = [
|
||||
"proc-macro-crate",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.66",
|
||||
"syn 2.0.99",
|
||||
"zvariant_utils",
|
||||
]
|
||||
|
||||
@@ -3661,5 +3785,5 @@ checksum = "fc242db087efc22bd9ade7aa7809e4ba828132edc312871584a6b4391bdf8786"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.66",
|
||||
"syn 2.0.99",
|
||||
]
|
||||
|
||||
@@ -5,8 +5,8 @@ categories = ["os"]
|
||||
keywords = ["upgrade", "update"]
|
||||
license = "GPL-3.0"
|
||||
repository = "https://github.com/topgrade-rs/topgrade"
|
||||
rust-version = "1.76.0"
|
||||
version = "16.0.1"
|
||||
rust-version = "1.84.1"
|
||||
version = "16.0.3"
|
||||
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"
|
||||
@@ -54,6 +54,7 @@ notify-rust = "~4.11"
|
||||
wildmatch = "2.3.0"
|
||||
rust-i18n = "3.0.1"
|
||||
sys-locale = "0.3.1"
|
||||
jetbrains-toolbox-updater = "1.1.0"
|
||||
|
||||
[package.metadata.generate-rpm]
|
||||
assets = [{ source = "target/release/topgrade", dest = "/usr/bin/topgrade" }]
|
||||
|
||||
@@ -31,6 +31,7 @@ To remedy this, **Topgrade** detects which tools you use and runs the appropriat
|
||||
- macOS: [Homebrew](https://formulae.brew.sh/formula/topgrade) or [MacPorts](https://ports.macports.org/port/topgrade/)
|
||||
- Windows: [Chocolatey][choco], [Scoop][scoop] or [Winget][winget]
|
||||
- PyPi: [pip](https://pypi.org/project/topgrade/)
|
||||
- Fedora: [Copr](https://copr.fedorainfracloud.org/coprs/lilay/topgrade/)
|
||||
|
||||
[choco]: https://community.chocolatey.org/packages/topgrade
|
||||
[scoop]: https://scoop.sh/#/apps?q=topgrade
|
||||
|
||||
@@ -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'
|
||||
|
||||
@@ -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: |
|
||||
|
||||
|
||||
@@ -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"
|
||||
@@ -207,6 +219,10 @@
|
||||
|
||||
# wsl_update_use_web_download = true
|
||||
|
||||
# The default for winget_install_silently is true,
|
||||
# this example turns off silent install.
|
||||
# winget_install_silently = false
|
||||
|
||||
# Causes Topgrade to rename itself during the run to allow package managers
|
||||
# to upgrade it. Use this only if you installed Topgrade by using a package
|
||||
# manager such as Scoop or Cargo
|
||||
@@ -223,6 +239,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 +286,42 @@
|
||||
# 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
|
||||
|
||||
[zigup]
|
||||
# Version strings passed to zigup.
|
||||
# These may be pinned versions such as "0.13.0" or branches such as "master".
|
||||
# Each one will be updated in its own zigup invocation.
|
||||
# (default: ["master"])
|
||||
# target_versions = ["master", "0.13.0"]
|
||||
|
||||
# Specifies the directory that the zig files will be installed to.
|
||||
# If defined, passed with the --install-dir command line flag.
|
||||
# If not defined, zigup will use its default behaviour.
|
||||
# (default: not defined)
|
||||
# install_dir = "~/.zig"
|
||||
|
||||
# Specifies the path of the symlink which will be set to point at the default compiler version.
|
||||
# If defined, passed with the --path-link command line flag.
|
||||
# If not defined, zigup will use its default behaviour.
|
||||
# This is not meaningful if set_default is not enabled.
|
||||
# (default: not defined)
|
||||
# path_link = "~/.bin/zig"
|
||||
|
||||
# If enabled, run `zigup clean` after updating all versions.
|
||||
# If enabled, each updated version above will be marked with `zigup keep`.
|
||||
# (default: false)
|
||||
# cleanup = false
|
||||
|
||||
[vscode]
|
||||
# If this is set and is a non-empty string, it specifies the profile the
|
||||
# extensions should be updated for.
|
||||
# (default: this won't be set by default)
|
||||
# profile = ""
|
||||
|
||||
836
locales/app.yml
836
locales/app.yml
File diff suppressed because it is too large
Load Diff
@@ -1,2 +1,2 @@
|
||||
[toolchain]
|
||||
channel = "1.76.0"
|
||||
channel = "1.84.1"
|
||||
|
||||
@@ -45,13 +45,13 @@ impl TryFrom<&Output> for Utf8Output {
|
||||
type Error = eyre::Error;
|
||||
|
||||
fn try_from(Output { status, stdout, stderr }: &Output) -> Result<Self, Self::Error> {
|
||||
let stdout = String::from_utf8(stdout.to_vec()).map_err(|err| {
|
||||
let stdout = String::from_utf8(stdout.clone()).map_err(|err| {
|
||||
eyre!(
|
||||
"Stdout contained invalid UTF-8: {}",
|
||||
String::from_utf8_lossy(err.as_bytes())
|
||||
)
|
||||
})?;
|
||||
let stderr = String::from_utf8(stderr.to_vec()).map_err(|err| {
|
||||
let stderr = String::from_utf8(stderr.clone()).map_err(|err| {
|
||||
eyre!(
|
||||
"Stderr contained invalid UTF-8: {}",
|
||||
String::from_utf8_lossy(err.as_bytes())
|
||||
@@ -149,6 +149,7 @@ pub trait CommandExt {
|
||||
/// Like [`Command::spawn`], but gives a nice error message if the command fails to
|
||||
/// execute.
|
||||
#[track_caller]
|
||||
#[allow(dead_code)]
|
||||
fn spawn_checked(&mut self) -> eyre::Result<Self::Child>;
|
||||
}
|
||||
|
||||
|
||||
162
src/config.rs
162
src/config.rs
@@ -69,6 +69,7 @@ pub enum Step {
|
||||
Chezmoi,
|
||||
Chocolatey,
|
||||
Choosenim,
|
||||
CinnamonSpices,
|
||||
ClamAvDb,
|
||||
Composer,
|
||||
Conda,
|
||||
@@ -97,6 +98,7 @@ pub enum Step {
|
||||
Haxelib,
|
||||
Helm,
|
||||
HomeManager,
|
||||
JetBrainsToolbox,
|
||||
Jetpack,
|
||||
Julia,
|
||||
Juliaup,
|
||||
@@ -111,6 +113,7 @@ pub enum Step {
|
||||
Mas,
|
||||
Maza,
|
||||
Micro,
|
||||
MicrosoftStore,
|
||||
Mise,
|
||||
Myrepos,
|
||||
Nix,
|
||||
@@ -124,6 +127,7 @@ pub enum Step {
|
||||
PipReviewLocal,
|
||||
Pipupgrade,
|
||||
Pipx,
|
||||
Pipxu,
|
||||
Pixi,
|
||||
Pkg,
|
||||
Pkgin,
|
||||
@@ -162,6 +166,7 @@ pub enum Step {
|
||||
Vim,
|
||||
VoltaPackages,
|
||||
Vscode,
|
||||
Vscodium,
|
||||
Waydroid,
|
||||
Winget,
|
||||
Wsl,
|
||||
@@ -169,6 +174,7 @@ pub enum Step {
|
||||
Xcodes,
|
||||
Yadm,
|
||||
Yarn,
|
||||
Zigup,
|
||||
Zvm,
|
||||
}
|
||||
|
||||
@@ -219,6 +225,7 @@ pub struct Windows {
|
||||
open_remotes_in_new_terminal: Option<bool>,
|
||||
wsl_update_pre_release: Option<bool>,
|
||||
wsl_update_use_web_download: Option<bool>,
|
||||
winget_silent_install: Option<bool>,
|
||||
}
|
||||
|
||||
#[derive(Deserialize, Default, Debug, Merge)]
|
||||
@@ -228,6 +235,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 +262,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 +365,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 +460,27 @@ 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)]
|
||||
pub struct Zigup {
|
||||
target_versions: Option<Vec<String>>,
|
||||
install_dir: Option<String>,
|
||||
path_link: Option<String>,
|
||||
cleanup: Option<bool>,
|
||||
}
|
||||
|
||||
#[derive(Deserialize, Default, Debug, Merge)]
|
||||
#[serde(deny_unknown_fields)]
|
||||
pub struct VscodeConfig {
|
||||
profile: Option<String>,
|
||||
}
|
||||
|
||||
#[derive(Deserialize, Default, Debug, Merge)]
|
||||
#[serde(deny_unknown_fields)]
|
||||
/// Configuration file
|
||||
@@ -490,6 +527,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 +547,15 @@ 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>,
|
||||
|
||||
#[merge(strategy = crate::utils::merge_strategies::inner_merge_opt)]
|
||||
zigup: Option<Zigup>,
|
||||
|
||||
#[merge(strategy = crate::utils::merge_strategies::inner_merge_opt)]
|
||||
vscode: Option<VscodeConfig>,
|
||||
}
|
||||
|
||||
fn config_directory() -> PathBuf {
|
||||
@@ -538,7 +587,7 @@ impl ConfigFile {
|
||||
];
|
||||
|
||||
// Search for the main config file
|
||||
for path in possible_config_paths.iter() {
|
||||
for path in &possible_config_paths {
|
||||
if path.exists() {
|
||||
debug!("Configuration at {}", path.display());
|
||||
res.0.clone_from(path);
|
||||
@@ -802,7 +851,7 @@ pub struct CommandLineArgs {
|
||||
|
||||
/// Tracing filter directives.
|
||||
///
|
||||
/// See: https://docs.rs/tracing-subscriber/latest/tracing_subscriber/struct.EnvFilter.html
|
||||
/// See: https://docs.rs/tracing-subscriber/latest/tracing_subscriber/filter/struct.EnvFilter.html#directives
|
||||
#[arg(long, default_value = DEFAULT_LOG_LEVEL)]
|
||||
pub log_filter: String,
|
||||
|
||||
@@ -1437,14 +1486,22 @@ 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
|
||||
.misc
|
||||
.as_ref()
|
||||
.and_then(|misc| misc.ignore_failures.as_ref())
|
||||
.map(|v| v.contains(&step))
|
||||
.unwrap_or(false)
|
||||
.is_some_and(|v| v.contains(&step))
|
||||
}
|
||||
|
||||
pub fn use_predefined_git_repos(&self) -> bool {
|
||||
@@ -1494,6 +1551,14 @@ impl Config {
|
||||
.unwrap_or(false)
|
||||
}
|
||||
|
||||
pub fn winget_silent_install(&self) -> bool {
|
||||
self.config_file
|
||||
.windows
|
||||
.as_ref()
|
||||
.and_then(|windows| windows.winget_silent_install)
|
||||
.unwrap_or(true)
|
||||
}
|
||||
|
||||
pub fn sudo_command(&self) -> Option<SudoKind> {
|
||||
self.config_file.misc.as_ref().and_then(|misc| misc.sudo_command)
|
||||
}
|
||||
@@ -1525,6 +1590,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 +1635,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 +1649,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 +1693,55 @@ 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)
|
||||
}
|
||||
|
||||
pub fn zigup_target_versions(&self) -> Vec<String> {
|
||||
self.config_file
|
||||
.zigup
|
||||
.as_ref()
|
||||
.and_then(|zigup| zigup.target_versions.clone())
|
||||
.unwrap_or(vec!["master".to_owned()])
|
||||
}
|
||||
|
||||
pub fn zigup_install_dir(&self) -> Option<&str> {
|
||||
self.config_file
|
||||
.zigup
|
||||
.as_ref()
|
||||
.and_then(|zigup| zigup.install_dir.as_deref())
|
||||
}
|
||||
|
||||
pub fn zigup_path_link(&self) -> Option<&str> {
|
||||
self.config_file
|
||||
.zigup
|
||||
.as_ref()
|
||||
.and_then(|zigup| zigup.path_link.as_deref())
|
||||
}
|
||||
|
||||
pub fn zigup_cleanup(&self) -> bool {
|
||||
self.config_file
|
||||
.zigup
|
||||
.as_ref()
|
||||
.and_then(|zigup| zigup.cleanup)
|
||||
.unwrap_or(false)
|
||||
}
|
||||
|
||||
pub fn vscode_profile(&self) -> Option<&str> {
|
||||
let vscode_cfg = self.config_file.vscode.as_ref()?;
|
||||
let profile = vscode_cfg.profile.as_ref()?;
|
||||
|
||||
if profile.is_empty() {
|
||||
None
|
||||
} else {
|
||||
Some(profile.as_str())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
@@ -1646,40 +1768,40 @@ mod test {
|
||||
|
||||
#[test]
|
||||
fn test_should_execute_remote_different_hostname() {
|
||||
assert!(config().should_execute_remote(Ok("hostname".to_string()), "remote_hostname"))
|
||||
assert!(config().should_execute_remote(Ok("hostname".to_string()), "remote_hostname"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_should_execute_remote_different_hostname_with_user() {
|
||||
assert!(config().should_execute_remote(Ok("hostname".to_string()), "user@remote_hostname"))
|
||||
assert!(config().should_execute_remote(Ok("hostname".to_string()), "user@remote_hostname"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_should_execute_remote_unknown_hostname() {
|
||||
assert!(config().should_execute_remote(Err(eyre!("failed to get hostname")), "remote_hostname"))
|
||||
assert!(config().should_execute_remote(Err(eyre!("failed to get hostname")), "remote_hostname"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_should_not_execute_remote_same_hostname() {
|
||||
assert!(!config().should_execute_remote(Ok("hostname".to_string()), "hostname"))
|
||||
assert!(!config().should_execute_remote(Ok("hostname".to_string()), "hostname"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_should_not_execute_remote_same_hostname_with_user() {
|
||||
assert!(!config().should_execute_remote(Ok("hostname".to_string()), "user@hostname"))
|
||||
assert!(!config().should_execute_remote(Ok("hostname".to_string()), "user@hostname"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_should_execute_remote_matching_limit() {
|
||||
let mut config = config();
|
||||
config.opt = CommandLineArgs::parse_from(["topgrade", "--remote-host-limit", "remote_hostname"]);
|
||||
assert!(config.should_execute_remote(Ok("hostname".to_string()), "user@remote_hostname"))
|
||||
assert!(config.should_execute_remote(Ok("hostname".to_string()), "user@remote_hostname"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_should_not_execute_remote_not_matching_limit() {
|
||||
let mut config = config();
|
||||
config.opt = CommandLineArgs::parse_from(["topgrade", "--remote-host-limit", "other_hostname"]);
|
||||
assert!(!config.should_execute_remote(Ok("hostname".to_string()), "user@remote_hostname"))
|
||||
assert!(!config.should_execute_remote(Ok("hostname".to_string()), "user@remote_hostname"));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -11,9 +11,9 @@ pub fn interrupted() -> bool {
|
||||
/// Clears the interrupted flag
|
||||
pub fn unset_interrupted() {
|
||||
debug_assert!(INTERRUPTED.load(Ordering::SeqCst));
|
||||
INTERRUPTED.store(false, Ordering::SeqCst)
|
||||
INTERRUPTED.store(false, Ordering::SeqCst);
|
||||
}
|
||||
|
||||
pub fn set_interrupted() {
|
||||
INTERRUPTED.store(true, Ordering::SeqCst)
|
||||
INTERRUPTED.store(true, Ordering::SeqCst);
|
||||
}
|
||||
|
||||
@@ -4,7 +4,7 @@ use nix::sys::signal::{sigaction, SaFlags, SigAction, SigHandler, SigSet, Signal
|
||||
|
||||
/// Handle SIGINT. Set the interruption flag.
|
||||
extern "C" fn handle_sigint(_: i32) {
|
||||
set_interrupted()
|
||||
set_interrupted();
|
||||
}
|
||||
|
||||
/// Set the necessary signal handlers.
|
||||
|
||||
@@ -152,7 +152,10 @@ impl Executor {
|
||||
let result = match self {
|
||||
Executor::Wet(c) => {
|
||||
debug!("Running {:?}", c);
|
||||
c.spawn_checked().map(ExecutorChild::Wet)?
|
||||
// We should use `spawn()` here rather than `spawn_checked()` since
|
||||
// their semantics and behaviors are different.
|
||||
#[allow(clippy::disallowed_methods)]
|
||||
c.spawn().map(ExecutorChild::Wet)?
|
||||
}
|
||||
Executor::Dry(c) => {
|
||||
c.dry_run();
|
||||
@@ -166,7 +169,12 @@ impl Executor {
|
||||
/// See `std::process::Command::output`
|
||||
pub fn output(&mut self) -> Result<ExecutorOutput> {
|
||||
match self {
|
||||
Executor::Wet(c) => Ok(ExecutorOutput::Wet(c.output_checked()?)),
|
||||
Executor::Wet(c) => {
|
||||
// We should use `output()` here rather than `output_checked()` since
|
||||
// their semantics and behaviors are different.
|
||||
#[allow(clippy::disallowed_methods)]
|
||||
Ok(ExecutorOutput::Wet(c.output()?))
|
||||
}
|
||||
Executor::Dry(c) => {
|
||||
c.dry_run();
|
||||
Ok(ExecutorOutput::Dry)
|
||||
@@ -180,7 +188,7 @@ impl Executor {
|
||||
pub fn status_checked_with_codes(&mut self, codes: &[i32]) -> Result<()> {
|
||||
match self {
|
||||
Executor::Wet(c) => c.status_checked_with(|status| {
|
||||
if status.success() || status.code().as_ref().map(|c| codes.contains(c)).unwrap_or(false) {
|
||||
if status.success() || status.code().as_ref().is_some_and(|c| codes.contains(c)) {
|
||||
Ok(())
|
||||
} else {
|
||||
Err(())
|
||||
|
||||
25
src/main.rs
25
src/main.rs
@@ -25,7 +25,9 @@ use self::config::{CommandLineArgs, Config, Step};
|
||||
use self::error::StepFailed;
|
||||
#[cfg(all(windows, feature = "self-update"))]
|
||||
use self::error::Upgraded;
|
||||
#[allow(clippy::wildcard_imports)]
|
||||
use self::steps::{remote::*, *};
|
||||
#[allow(clippy::wildcard_imports)]
|
||||
use self::terminal::*;
|
||||
|
||||
use self::utils::{hostname, install_color_eyre, install_tracing, update_tracing};
|
||||
@@ -58,6 +60,7 @@ pub(crate) static WINDOWS_DIRS: Lazy<Windows> = Lazy::new(|| Windows::new().expe
|
||||
// Init and load the i18n files
|
||||
i18n!("locales", fallback = "en");
|
||||
|
||||
#[allow(clippy::too_many_lines)]
|
||||
fn run() -> Result<()> {
|
||||
install_color_eyre()?;
|
||||
ctrlc::set_handler();
|
||||
@@ -206,6 +209,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")]
|
||||
@@ -245,6 +251,9 @@ fn run() -> Result<()> {
|
||||
runner.execute(Step::Lure, "LURE", || linux::run_lure_update(&ctx))?;
|
||||
runner.execute(Step::Waydroid, "Waydroid", || linux::run_waydroid(&ctx))?;
|
||||
runner.execute(Step::AutoCpufreq, "auto-cpufreq", || linux::run_auto_cpufreq(&ctx))?;
|
||||
runner.execute(Step::CinnamonSpices, "Cinnamon spices", || {
|
||||
linux::run_cinnamon_spices_updater(&ctx)
|
||||
})?;
|
||||
}
|
||||
|
||||
#[cfg(target_os = "macos")]
|
||||
@@ -366,9 +375,13 @@ fn run() -> Result<()> {
|
||||
runner.execute(Step::Opam, "opam", || generic::run_opam_update(&ctx))?;
|
||||
runner.execute(Step::Vcpkg, "vcpkg", || generic::run_vcpkg_update(&ctx))?;
|
||||
runner.execute(Step::Pipx, "pipx", || generic::run_pipx_update(&ctx))?;
|
||||
runner.execute(Step::Pipxu, "pipxu", || generic::run_pipxu_update(&ctx))?;
|
||||
runner.execute(Step::Vscode, "Visual Studio Code extensions", || {
|
||||
generic::run_vscode_extensions_update(&ctx)
|
||||
})?;
|
||||
runner.execute(Step::Vscodium, "VSCodium extensions", || {
|
||||
generic::run_vscodium_extensions_update(&ctx)
|
||||
})?;
|
||||
runner.execute(Step::Conda, "conda", || generic::run_conda_update(&ctx))?;
|
||||
runner.execute(Step::Mamba, "mamba", || generic::run_mamba_update(&ctx))?;
|
||||
runner.execute(Step::Pixi, "pixi", || generic::run_pixi_update(&ctx))?;
|
||||
@@ -432,6 +445,10 @@ fn run() -> Result<()> {
|
||||
runner.execute(Step::Zvm, "ZVM", || generic::run_zvm(&ctx))?;
|
||||
runner.execute(Step::Aqua, "aqua", || generic::run_aqua(&ctx))?;
|
||||
runner.execute(Step::Bun, "bun", || generic::run_bun(&ctx))?;
|
||||
runner.execute(Step::Zigup, "zigup", || generic::run_zigup(&ctx))?;
|
||||
runner.execute(Step::JetBrainsToolbox, "JetBrains Toolbox", || {
|
||||
generic::run_jetbrains_toolbox(&ctx)
|
||||
})?;
|
||||
|
||||
if should_run_powershell {
|
||||
runner.execute(Step::Powershell, "Powershell Modules Update", || {
|
||||
@@ -488,13 +505,13 @@ fn run() -> Result<()> {
|
||||
print_info(t!("\n(R)eboot\n(S)hell\n(Q)uit"));
|
||||
loop {
|
||||
match get_key() {
|
||||
Ok(Key::Char('s')) | Ok(Key::Char('S')) => {
|
||||
Ok(Key::Char('s' | 'S')) => {
|
||||
run_shell().context("Failed to execute shell")?;
|
||||
}
|
||||
Ok(Key::Char('r')) | Ok(Key::Char('R')) => {
|
||||
Ok(Key::Char('r' | 'R')) => {
|
||||
reboot().context("Failed to reboot")?;
|
||||
}
|
||||
Ok(Key::Char('q')) | Ok(Key::Char('Q')) => (),
|
||||
Ok(Key::Char('q' | 'Q')) => (),
|
||||
_ => {
|
||||
continue;
|
||||
}
|
||||
@@ -513,7 +530,7 @@ fn run() -> Result<()> {
|
||||
t!("Topgrade finished successfully")
|
||||
},
|
||||
Some(Duration::from_secs(10)),
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
if failed {
|
||||
|
||||
@@ -9,7 +9,7 @@ use rust_i18n::t;
|
||||
use self_update_crate::backends::github::Update;
|
||||
use self_update_crate::update::UpdateStatus;
|
||||
|
||||
use super::terminal::*;
|
||||
use super::terminal::{print_info, print_separator};
|
||||
#[cfg(windows)]
|
||||
use crate::error::Upgraded;
|
||||
|
||||
|
||||
@@ -140,7 +140,7 @@ pub fn run_containers(ctx: &ExecutionContext) -> Result<()> {
|
||||
list_containers(&crt, ctx.config().containers_ignored_tags()).context("Failed to list Docker containers")?;
|
||||
debug!("Containers to inspect: {:?}", containers);
|
||||
|
||||
for container in containers.iter() {
|
||||
for container in &containers {
|
||||
debug!("Pulling container '{}'", container);
|
||||
let args = vec![
|
||||
"pull",
|
||||
|
||||
@@ -1,9 +1,4 @@
|
||||
(when (fboundp 'paradox-upgrade-packages)
|
||||
(progn
|
||||
(unless (boundp 'paradox-github-token)
|
||||
(setq paradox-github-token t))
|
||||
(paradox-upgrade-packages)
|
||||
(princ
|
||||
(if (get-buffer "*Paradox Report*")
|
||||
(with-current-buffer "*Paradox Report*" (buffer-string))
|
||||
"\nNothing to upgrade\n"))))
|
||||
(when (featurep 'package)
|
||||
(if (fboundp 'package-upgrade-all)
|
||||
(package-upgrade-all nil)
|
||||
(message "Your Emacs version doesn't support unattended packages upgrade")))
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
#![allow(unused_imports)]
|
||||
|
||||
use std::ffi::{OsStr, OsString};
|
||||
use std::path::PathBuf;
|
||||
use std::process::Command;
|
||||
use std::{env, path::Path};
|
||||
@@ -8,6 +9,9 @@ use std::{fs, io::Write};
|
||||
use color_eyre::eyre::eyre;
|
||||
use color_eyre::eyre::Context;
|
||||
use color_eyre::eyre::Result;
|
||||
use jetbrains_toolbox_updater::{find_jetbrains_toolbox, update_jetbrains_toolbox, FindError};
|
||||
use lazy_static::lazy_static;
|
||||
use regex::bytes::Regex;
|
||||
use rust_i18n::t;
|
||||
use semver::Version;
|
||||
use tempfile::tempfile_in;
|
||||
@@ -39,8 +43,7 @@ pub fn is_wsl() -> Result<bool> {
|
||||
|
||||
pub fn run_cargo_update(ctx: &ExecutionContext) -> Result<()> {
|
||||
let cargo_dir = env::var_os("CARGO_HOME")
|
||||
.map(PathBuf::from)
|
||||
.unwrap_or_else(|| HOME_DIR.join(".cargo"))
|
||||
.map_or_else(|| HOME_DIR.join(".cargo"), PathBuf::from)
|
||||
.require()?;
|
||||
require("cargo").or_else(|_| {
|
||||
require_option(
|
||||
@@ -59,13 +62,11 @@ pub fn run_cargo_update(ctx: &ExecutionContext) -> Result<()> {
|
||||
let cargo_update = require("cargo-install-update")
|
||||
.ok()
|
||||
.or_else(|| cargo_dir.join("bin/cargo-install-update").if_exists());
|
||||
let cargo_update = match cargo_update {
|
||||
Some(e) => e,
|
||||
None => {
|
||||
let message = String::from("cargo-update isn't installed so Topgrade can't upgrade cargo packages.\nInstall cargo-update by running `cargo install cargo-update`");
|
||||
print_warning(&message);
|
||||
return Err(SkipStep(message).into());
|
||||
}
|
||||
|
||||
let Some(cargo_update) = cargo_update else {
|
||||
let message = String::from("cargo-update isn't installed so Topgrade can't upgrade cargo packages.\nInstall cargo-update by running `cargo install cargo-update`");
|
||||
print_warning(&message);
|
||||
return Err(SkipStep(message).into());
|
||||
};
|
||||
|
||||
ctx.run_type()
|
||||
@@ -77,14 +78,11 @@ pub fn run_cargo_update(ctx: &ExecutionContext) -> Result<()> {
|
||||
let cargo_cache = require("cargo-cache")
|
||||
.ok()
|
||||
.or_else(|| cargo_dir.join("bin/cargo-cache").if_exists());
|
||||
match cargo_cache {
|
||||
Some(e) => {
|
||||
ctx.run_type().execute(e).args(["-a"]).status_checked()?;
|
||||
}
|
||||
None => {
|
||||
let message = String::from("cargo-cache isn't installed so Topgrade can't cleanup cargo packages.\nInstall cargo-cache by running `cargo install cargo-cache`");
|
||||
print_warning(message);
|
||||
}
|
||||
if let Some(e) = cargo_cache {
|
||||
ctx.run_type().execute(e).args(["-a"]).status_checked()?;
|
||||
} else {
|
||||
let message = String::from("cargo-cache isn't installed so Topgrade can't cleanup cargo packages.\nInstall cargo-cache by running `cargo install cargo-cache`");
|
||||
print_warning(message);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -228,6 +226,13 @@ pub fn run_apm(ctx: &ExecutionContext) -> Result<()> {
|
||||
pub fn run_aqua(ctx: &ExecutionContext) -> Result<()> {
|
||||
let aqua = require("aqua")?;
|
||||
|
||||
// Check if `aqua --help` mentions "aqua". JetBrains aqua does not, aqua CLI does.
|
||||
let output = ctx.run_type().execute(&aqua).arg("--help").output_checked()?;
|
||||
|
||||
if !String::from_utf8(output.stdout)?.contains("aqua") {
|
||||
return Err(SkipStep("Command aqua probably points to JetBrains Aqua".to_string()).into());
|
||||
}
|
||||
|
||||
print_separator("Aqua");
|
||||
if ctx.run_type().dry() {
|
||||
println!("{}", t!("Updating aqua ..."));
|
||||
@@ -257,10 +262,35 @@ pub fn run_elan(ctx: &ExecutionContext) -> Result<()> {
|
||||
let elan = require("elan")?;
|
||||
|
||||
print_separator("elan");
|
||||
ctx.run_type()
|
||||
.execute(&elan)
|
||||
.args(["self", "update"])
|
||||
.status_checked()?;
|
||||
|
||||
let disabled_error_msg = "self-update is disabled";
|
||||
let executor_output = ctx.run_type().execute(&elan).args(["self", "update"]).output()?;
|
||||
match executor_output {
|
||||
ExecutorOutput::Wet(command_output) => {
|
||||
if command_output.status.success() {
|
||||
// Flush the captured output
|
||||
std::io::stdout().lock().write_all(&command_output.stdout).unwrap();
|
||||
std::io::stderr().lock().write_all(&command_output.stderr).unwrap();
|
||||
} else {
|
||||
let stderr_as_str = std::str::from_utf8(&command_output.stderr).unwrap();
|
||||
if stderr_as_str.contains(disabled_error_msg) {
|
||||
// `elan` is externally managed, we cannot do the update. Users
|
||||
// won't see any error message because Topgrade captures them
|
||||
// all.
|
||||
} else {
|
||||
// `elan` is NOT externally managed, `elan self update` can
|
||||
// be performed, but the invocation failed, so we report the
|
||||
// error to the user and error out.
|
||||
std::io::stdout().lock().write_all(&command_output.stdout).unwrap();
|
||||
std::io::stderr().lock().write_all(&command_output.stderr).unwrap();
|
||||
|
||||
return Err(StepFailed.into());
|
||||
}
|
||||
}
|
||||
}
|
||||
ExecutorOutput::Dry => { /* nothing needed because in a dry run */ }
|
||||
}
|
||||
|
||||
ctx.run_type().execute(&elan).arg("update").status_checked()
|
||||
}
|
||||
|
||||
@@ -276,7 +306,13 @@ pub fn run_juliaup(ctx: &ExecutionContext) -> Result<()> {
|
||||
.status_checked()?;
|
||||
}
|
||||
|
||||
ctx.run_type().execute(&juliaup).arg("update").status_checked()
|
||||
ctx.run_type().execute(&juliaup).arg("update").status_checked()?;
|
||||
|
||||
if ctx.config().cleanup() {
|
||||
ctx.run_type().execute(&juliaup).arg("gc").status_checked()?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn run_choosenim(ctx: &ExecutionContext) -> Result<()> {
|
||||
@@ -374,6 +410,48 @@ pub fn run_vcpkg_update(ctx: &ExecutionContext) -> Result<()> {
|
||||
command.args(["upgrade", "--no-dry-run"]).status_checked()
|
||||
}
|
||||
|
||||
/// Make VSCodium a separate step because:
|
||||
///
|
||||
/// 1. Users could use both VSCode and VSCodium
|
||||
/// 2. Just in case, VSCodium could have incompatible changes with VSCode
|
||||
pub fn run_vscodium_extensions_update(ctx: &ExecutionContext) -> Result<()> {
|
||||
// Calling vscodoe in WSL may install a server instead of updating extensions (https://github.com/topgrade-rs/topgrade/issues/594#issuecomment-1782157367)
|
||||
if is_wsl()? {
|
||||
return Err(SkipStep(String::from("Should not run in WSL")).into());
|
||||
}
|
||||
|
||||
let vscodium = require("codium")?;
|
||||
|
||||
// VSCode has update command only since 1.86 version ("january 2024" update), disable the update for prior versions
|
||||
// Use command `code --version` which returns 3 lines: version, git commit, instruction set. We parse only the first one
|
||||
//
|
||||
// This should apply to VSCodium as well.
|
||||
let version: Result<Version> = match Command::new(&vscodium)
|
||||
.arg("--version")
|
||||
.output_checked_utf8()?
|
||||
.stdout
|
||||
.lines()
|
||||
.next()
|
||||
{
|
||||
Some(item) => Version::parse(item).map_err(std::convert::Into::into),
|
||||
_ => return Err(SkipStep(String::from("Cannot find vscodium version")).into()),
|
||||
};
|
||||
|
||||
if !matches!(version, Ok(version) if version >= Version::new(1, 86, 0)) {
|
||||
return Err(SkipStep(String::from(
|
||||
"Too old vscodium version to have update extensions command",
|
||||
))
|
||||
.into());
|
||||
}
|
||||
|
||||
print_separator("VSCodium extensions");
|
||||
|
||||
ctx.run_type()
|
||||
.execute(vscodium)
|
||||
.arg("--update-extensions")
|
||||
.status_checked()
|
||||
}
|
||||
|
||||
pub fn run_vscode_extensions_update(ctx: &ExecutionContext) -> Result<()> {
|
||||
// Calling vscode in WSL may install a server instead of updating extensions (https://github.com/topgrade-rs/topgrade/issues/594#issuecomment-1782157367)
|
||||
if is_wsl()? {
|
||||
@@ -391,7 +469,7 @@ pub fn run_vscode_extensions_update(ctx: &ExecutionContext) -> Result<()> {
|
||||
.lines()
|
||||
.next()
|
||||
{
|
||||
Some(item) => Version::parse(item).map_err(|err| err.into()),
|
||||
Some(item) => Version::parse(item).map_err(std::convert::Into::into),
|
||||
_ => return Err(SkipStep(String::from("Cannot find vscode version")).into()),
|
||||
};
|
||||
|
||||
@@ -401,10 +479,19 @@ pub fn run_vscode_extensions_update(ctx: &ExecutionContext) -> Result<()> {
|
||||
|
||||
print_separator("Visual Studio Code extensions");
|
||||
|
||||
ctx.run_type()
|
||||
.execute(vscode)
|
||||
.arg("--update-extensions")
|
||||
.status_checked()
|
||||
if let Some(profile) = ctx.config().vscode_profile() {
|
||||
ctx.run_type()
|
||||
.execute(vscode)
|
||||
.arg("--profile")
|
||||
.arg(profile)
|
||||
.arg("--update-extensions")
|
||||
.status_checked()
|
||||
} else {
|
||||
ctx.run_type()
|
||||
.execute(vscode)
|
||||
.arg("--update-extensions")
|
||||
.status_checked()
|
||||
}
|
||||
}
|
||||
|
||||
pub fn run_pipx_update(ctx: &ExecutionContext) -> Result<()> {
|
||||
@@ -421,12 +508,22 @@ pub fn run_pipx_update(ctx: &ExecutionContext) -> Result<()> {
|
||||
.map(|s| s.stdout.trim().to_owned());
|
||||
let version = Version::parse(&version_str?);
|
||||
if matches!(version, Ok(version) if version >= Version::new(1, 4, 0)) {
|
||||
command_args.push("--quiet")
|
||||
command_args.push("--quiet");
|
||||
}
|
||||
|
||||
ctx.run_type().execute(pipx).args(command_args).status_checked()
|
||||
}
|
||||
|
||||
pub fn run_pipxu_update(ctx: &ExecutionContext) -> Result<()> {
|
||||
let pipxu = require("pipxu")?;
|
||||
print_separator("pipxu");
|
||||
|
||||
ctx.run_type()
|
||||
.execute(pipxu)
|
||||
.args(["upgrade", "--all"])
|
||||
.status_checked()
|
||||
}
|
||||
|
||||
pub fn run_conda_update(ctx: &ExecutionContext) -> Result<()> {
|
||||
let conda = require("conda")?;
|
||||
|
||||
@@ -440,19 +537,45 @@ pub fn run_conda_update(ctx: &ExecutionContext) -> Result<()> {
|
||||
|
||||
print_separator("Conda");
|
||||
|
||||
let mut command = ctx.run_type().execute(conda);
|
||||
let mut command = ctx.run_type().execute(&conda);
|
||||
command.args(["update", "--all", "-n", "base"]);
|
||||
if ctx.config().yes(Step::Conda) {
|
||||
command.arg("--yes");
|
||||
}
|
||||
command.status_checked()
|
||||
command.status_checked()?;
|
||||
|
||||
if ctx.config().cleanup() {
|
||||
let mut command = ctx.run_type().execute(conda);
|
||||
command.args(["clean", "--all"]);
|
||||
if ctx.config().yes(Step::Conda) {
|
||||
command.arg("--yes");
|
||||
}
|
||||
command.status_checked()?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn run_pixi_update(ctx: &ExecutionContext) -> Result<()> {
|
||||
let pixi = require("pixi")?;
|
||||
print_separator("Pixi");
|
||||
|
||||
ctx.run_type().execute(pixi).args(["self-update"]).status_checked()
|
||||
// Check if `pixi --help` mentions self-update, if yes, self-update must be enabled.
|
||||
// pixi self-update --help works regardless of whether the feature is enabled.
|
||||
let output = ctx.run_type().execute(&pixi).arg("--help").output_checked()?;
|
||||
|
||||
if String::from_utf8(output.stdout)?.contains("self-update") {
|
||||
ctx.run_type()
|
||||
.execute(&pixi)
|
||||
.args(["self-update"])
|
||||
.status_checked()
|
||||
.ok();
|
||||
}
|
||||
|
||||
ctx.run_type()
|
||||
.execute(&pixi)
|
||||
.args(["global", "update"])
|
||||
.status_checked()
|
||||
}
|
||||
|
||||
pub fn run_mamba_update(ctx: &ExecutionContext) -> Result<()> {
|
||||
@@ -460,12 +583,23 @@ pub fn run_mamba_update(ctx: &ExecutionContext) -> Result<()> {
|
||||
|
||||
print_separator("Mamba");
|
||||
|
||||
let mut command = ctx.run_type().execute(mamba);
|
||||
let mut command = ctx.run_type().execute(&mamba);
|
||||
command.args(["update", "--all", "-n", "base"]);
|
||||
if ctx.config().yes(Step::Mamba) {
|
||||
command.arg("--yes");
|
||||
}
|
||||
command.status_checked()
|
||||
command.status_checked()?;
|
||||
|
||||
if ctx.config().cleanup() {
|
||||
let mut command = ctx.run_type().execute(&mamba);
|
||||
command.args(["clean", "--all"]);
|
||||
if ctx.config().yes(Step::Mamba) {
|
||||
command.arg("--yes");
|
||||
}
|
||||
command.status_checked()?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn run_miktex_packages_update(ctx: &ExecutionContext) -> Result<()> {
|
||||
@@ -487,7 +621,7 @@ pub fn run_pip3_update(ctx: &ExecutionContext) -> Result<()> {
|
||||
(Ok(py), _) => py,
|
||||
(Err(_), Ok(py3)) => py3,
|
||||
(Err(py_err), Err(py3_err)) => {
|
||||
return Err(SkipStep(format!("Skip due to following reasons: {} {}", py_err, py3_err)).into());
|
||||
return Err(SkipStep(format!("Skip due to following reasons: {py_err} {py3_err}")).into());
|
||||
}
|
||||
};
|
||||
|
||||
@@ -836,7 +970,7 @@ pub fn run_dotnet_upgrade(ctx: &ExecutionContext) -> Result<()> {
|
||||
.execute(&dotnet)
|
||||
.args(["tool", "update", package_name, "--global"])
|
||||
.status_checked()
|
||||
.with_context(|| format!("Failed to update .NET package {:?}", package_name))?;
|
||||
.with_context(|| format!("Failed to update .NET package {package_name:?}"))?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
@@ -908,10 +1042,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 +1163,133 @@ 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, Option<OsString>)> {
|
||||
// Parse the standard Unix shebang line: #!interpreter [optional-arg]
|
||||
// Spaces and tabs on either side of interpreter are ignored.
|
||||
|
||||
use std::os::unix::ffi::OsStrExt;
|
||||
|
||||
lazy_static! {
|
||||
static ref SHEBANG_REGEX: Regex = Regex::new(r"^#![ \t]*([^ \t\n]+)(?:[ \t]+([^\n]+)?)?").unwrap();
|
||||
}
|
||||
|
||||
let script = fs::read(poetry)?;
|
||||
if let Some(c) = SHEBANG_REGEX.captures(&script) {
|
||||
let interpreter = OsStr::from_bytes(&c[1]).into();
|
||||
let args = c.get(2).map(|args| OsStr::from_bytes(args.as_bytes()).into());
|
||||
return Ok((interpreter, args));
|
||||
}
|
||||
|
||||
Err(eyre!("Could not find shebang"))
|
||||
}
|
||||
#[cfg(windows)]
|
||||
fn get_interpreter(poetry: &PathBuf) -> Result<(PathBuf, Option<OsString>)> {
|
||||
// Parse the shebang line from scripts using https://bitbucket.org/vinay.sajip/simple_launcher,
|
||||
// such as those created by pip. In contrast to Unix shebang lines, interpreter paths can
|
||||
// contain spaces, if they are double-quoted.
|
||||
|
||||
use std::str;
|
||||
|
||||
lazy_static! {
|
||||
static ref SHEBANG_REGEX: Regex =
|
||||
Regex::new(r#"^#![ \t]*(?:"([^"\n]+)"|([^" \t\n]+))(?:[ \t]+([^\n]+)?)?"#).unwrap();
|
||||
}
|
||||
|
||||
let data = fs::read(poetry)?;
|
||||
|
||||
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;
|
||||
match data[..arc_pos].windows(2).rposition(|b| b == b"#!") {
|
||||
Some(l) => {
|
||||
let line = &data[l..arc_pos - 1];
|
||||
if let Some(c) = SHEBANG_REGEX.captures(line) {
|
||||
let interpreter = c.get(1).or_else(|| c.get(2)).unwrap();
|
||||
// shebang line should be valid utf8
|
||||
let interpreter = str::from_utf8(interpreter.as_bytes())?.into();
|
||||
let args = match c.get(3) {
|
||||
Some(args) => Some(str::from_utf8(args.as_bytes())?.into()),
|
||||
None => None,
|
||||
};
|
||||
Ok((interpreter, args))
|
||||
} else {
|
||||
Err(eyre!("Invalid shebang line"))
|
||||
}
|
||||
}
|
||||
None => Err(eyre!("Could not find shebang")),
|
||||
}
|
||||
}
|
||||
|
||||
if ctx.config().poetry_force_self_update() {
|
||||
debug!("forcing poetry self update");
|
||||
} else {
|
||||
let (interp, interp_args) = get_interpreter(&poetry)
|
||||
.map_err(|e| SkipStep(format!("Could not find interpreter for {}: {}", poetry.display(), e)))?;
|
||||
debug!("poetry interpreter: {:?}, args: {:?}", interp, interp_args);
|
||||
|
||||
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 mut command = Command::new(&interp);
|
||||
if let Some(args) = interp_args {
|
||||
command.arg(args);
|
||||
}
|
||||
let output = command
|
||||
.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");
|
||||
|
||||
ctx.run_type()
|
||||
// try uv self --help first - if it succeeds, we call uv self update
|
||||
let result = ctx
|
||||
.run_type()
|
||||
.execute(&uv_exec)
|
||||
.args(["self", "update"])
|
||||
.status_checked()
|
||||
.ok();
|
||||
.args(["self", "--help"])
|
||||
.output_checked();
|
||||
|
||||
// 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.
|
||||
if result.is_ok() {
|
||||
ctx.run_type()
|
||||
.execute(&uv_exec)
|
||||
.args(["self", "update"])
|
||||
.status_checked()?;
|
||||
}
|
||||
|
||||
ctx.run_type()
|
||||
.execute(&uv_exec)
|
||||
@@ -1064,3 +1313,87 @@ pub fn run_bun(ctx: &ExecutionContext) -> Result<()> {
|
||||
|
||||
ctx.run_type().execute(bun).arg("upgrade").status_checked()
|
||||
}
|
||||
|
||||
pub fn run_zigup(ctx: &ExecutionContext) -> Result<()> {
|
||||
let zigup = require("zigup")?;
|
||||
let config = ctx.config();
|
||||
|
||||
print_separator("zigup");
|
||||
|
||||
let mut path_args = Vec::new();
|
||||
if let Some(path) = config.zigup_path_link() {
|
||||
path_args.push("--path-link".to_owned());
|
||||
path_args.push(shellexpand::tilde(path).into_owned());
|
||||
}
|
||||
if let Some(path) = config.zigup_install_dir() {
|
||||
path_args.push("--install-dir".to_owned());
|
||||
path_args.push(shellexpand::tilde(path).into_owned());
|
||||
}
|
||||
|
||||
for zig_version in config.zigup_target_versions() {
|
||||
ctx.run_type()
|
||||
.execute(&zigup)
|
||||
.args(&path_args)
|
||||
.arg("fetch")
|
||||
.arg(&zig_version)
|
||||
.status_checked()?;
|
||||
|
||||
if config.zigup_cleanup() {
|
||||
ctx.run_type()
|
||||
.execute(&zigup)
|
||||
.args(&path_args)
|
||||
.arg("keep")
|
||||
.arg(&zig_version)
|
||||
.status_checked()?;
|
||||
}
|
||||
}
|
||||
|
||||
if config.zigup_cleanup() {
|
||||
ctx.run_type()
|
||||
.execute(zigup)
|
||||
.args(&path_args)
|
||||
.arg("clean")
|
||||
.status_checked()?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn run_jetbrains_toolbox(_ctx: &ExecutionContext) -> Result<()> {
|
||||
let installation = find_jetbrains_toolbox();
|
||||
match installation {
|
||||
Err(FindError::NotFound) => {
|
||||
// Skip
|
||||
Err(SkipStep(format!("{}", t!("No JetBrains Toolbox installation found"))).into())
|
||||
}
|
||||
Err(FindError::UnsupportedOS(os)) => {
|
||||
// Skip
|
||||
Err(SkipStep(format!("{}", t!("Unsupported operating system {os}", os = os))).into())
|
||||
}
|
||||
Err(e) => {
|
||||
// Unexpected error
|
||||
println!(
|
||||
"{}",
|
||||
t!("jetbrains-toolbox-updater encountered an unexpected error during finding:")
|
||||
);
|
||||
println!("{e:?}");
|
||||
Err(StepFailed.into())
|
||||
}
|
||||
Ok(installation) => {
|
||||
print_separator("JetBrains Toolbox");
|
||||
|
||||
match update_jetbrains_toolbox(installation) {
|
||||
Err(e) => {
|
||||
// Unexpected error
|
||||
println!(
|
||||
"{}",
|
||||
t!("jetbrains-toolbox-updater encountered an unexpected error during updating:")
|
||||
);
|
||||
println!("{e:?}");
|
||||
Err(StepFailed.into())
|
||||
}
|
||||
Ok(()) => Ok(()),
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -105,7 +105,7 @@ pub fn run_git_pull(ctx: &ExecutionContext) -> Result<()> {
|
||||
print_warning(t!(
|
||||
"Path {pattern} did not contain any git repositories",
|
||||
pattern = pattern
|
||||
))
|
||||
));
|
||||
});
|
||||
|
||||
if repos.is_repos_empty() {
|
||||
@@ -207,10 +207,13 @@ impl RepoStep {
|
||||
|
||||
return output;
|
||||
}
|
||||
Err(e) => match e.kind() {
|
||||
io::ErrorKind::NotFound => debug!("{} does not exist", path.as_ref().display()),
|
||||
_ => error!("Error looking for {}: {e}", path.as_ref().display(),),
|
||||
},
|
||||
Err(e) => {
|
||||
if e.kind() == io::ErrorKind::NotFound {
|
||||
debug!("{} does not exist", path.as_ref().display());
|
||||
} else {
|
||||
error!("Error looking for {}: {e}", path.as_ref().display());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
None
|
||||
@@ -321,7 +324,7 @@ impl RepoStep {
|
||||
.output()
|
||||
.await?;
|
||||
let result = output_checked_utf8(pull_output)
|
||||
.and_then(|_| output_checked_utf8(submodule_output))
|
||||
.and_then(|()| output_checked_utf8(submodule_output))
|
||||
.wrap_err_with(|| format!("Failed to pull {}", repo.as_ref().display()));
|
||||
|
||||
if result.is_err() {
|
||||
@@ -359,7 +362,7 @@ impl RepoStep {
|
||||
}
|
||||
}
|
||||
|
||||
result.map(|_| ())
|
||||
result
|
||||
}
|
||||
|
||||
/// Pull the repositories specified in `self.repos`.
|
||||
@@ -410,7 +413,7 @@ impl RepoStep {
|
||||
let basic_rt = runtime::Runtime::new()?;
|
||||
let results = basic_rt.block_on(async { stream_of_futures.collect::<Vec<Result<()>>>().await });
|
||||
|
||||
let error = results.into_iter().find(|r| r.is_err());
|
||||
let error = results.into_iter().find(std::result::Result::is_err);
|
||||
error.unwrap_or(Ok(()))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -87,7 +87,7 @@ impl NPM {
|
||||
.args(["--version"])
|
||||
.output_checked_utf8()
|
||||
.map(|s| s.stdout.trim().to_owned());
|
||||
Version::parse(&version_str?).map_err(|err| err.into())
|
||||
Version::parse(&version_str?).map_err(std::convert::Into::into)
|
||||
}
|
||||
|
||||
fn upgrade(&self, ctx: &ExecutionContext, use_sudo: bool) -> Result<()> {
|
||||
@@ -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(std::convert::Into::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
|
||||
@@ -313,7 +399,7 @@ pub fn run_volta_packages_upgrade(ctx: &ExecutionContext) -> Result<()> {
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
for package in installed_packages.iter() {
|
||||
for package in &installed_packages {
|
||||
ctx.run_type()
|
||||
.execute(&volta)
|
||||
.args(["install", package])
|
||||
|
||||
@@ -60,19 +60,7 @@ impl Distribution {
|
||||
Some("wolfi") => Distribution::Wolfi,
|
||||
Some("centos") | Some("rhel") | Some("ol") => Distribution::CentOS,
|
||||
Some("clear-linux-os") => Distribution::ClearLinux,
|
||||
Some("fedora") => {
|
||||
return if let Some(variant) = variant {
|
||||
match variant {
|
||||
"Silverblue" | "Kinoite" | "Sericea" | "Onyx" | "IoT Edition" | "Sway Atomic" => {
|
||||
Ok(Distribution::FedoraImmutable)
|
||||
}
|
||||
_ => Ok(Distribution::Fedora),
|
||||
}
|
||||
} else {
|
||||
Ok(Distribution::Fedora)
|
||||
};
|
||||
}
|
||||
|
||||
Some("fedora") => Distribution::match_fedora_variant(&variant),
|
||||
Some("nilrt") => Distribution::NILRT,
|
||||
Some("nobara") => Distribution::Nobara,
|
||||
Some("void") => Distribution::Void,
|
||||
@@ -109,7 +97,7 @@ impl Distribution {
|
||||
} else if id_like.contains(&"alpine") {
|
||||
return Ok(Distribution::Alpine);
|
||||
} else if id_like.contains(&"fedora") {
|
||||
return Ok(Distribution::Fedora);
|
||||
return Ok(Distribution::match_fedora_variant(&variant));
|
||||
}
|
||||
}
|
||||
return Err(TopgradeError::UnknownLinuxDistribution.into());
|
||||
@@ -117,6 +105,15 @@ impl Distribution {
|
||||
})
|
||||
}
|
||||
|
||||
fn match_fedora_variant(variant: &Option<&str>) -> Self {
|
||||
if let Some("Silverblue" | "Kinoite" | "Sericea" | "Onyx" | "IoT Edition" | "Sway Atomic" | "CoreOS") = variant
|
||||
{
|
||||
Distribution::FedoraImmutable
|
||||
} else {
|
||||
Distribution::Fedora
|
||||
}
|
||||
}
|
||||
|
||||
pub fn detect() -> Result<Self> {
|
||||
if PathBuf::from("/bedrock").exists() {
|
||||
return Ok(Distribution::Bedrock);
|
||||
@@ -225,6 +222,13 @@ fn upgrade_wolfi_linux(ctx: &ExecutionContext) -> Result<()> {
|
||||
}
|
||||
|
||||
fn upgrade_redhat(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();
|
||||
}
|
||||
}
|
||||
|
||||
if let Some(ostree) = which("rpm-ostree") {
|
||||
if ctx.config().rpm_ostree() {
|
||||
let mut command = ctx.run_type().execute(ostree);
|
||||
@@ -298,6 +302,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");
|
||||
@@ -1106,6 +1117,17 @@ pub fn run_auto_cpufreq(ctx: &ExecutionContext) -> Result<()> {
|
||||
.status_checked()
|
||||
}
|
||||
|
||||
pub fn run_cinnamon_spices_updater(ctx: &ExecutionContext) -> Result<()> {
|
||||
let cinnamon_spice_updater = require("cinnamon-spice-updater")?;
|
||||
|
||||
print_separator("Cinnamon spices");
|
||||
|
||||
ctx.run_type()
|
||||
.execute(cinnamon_spice_updater)
|
||||
.arg("--update-all")
|
||||
.status_checked()
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
@@ -1274,4 +1296,24 @@ mod tests {
|
||||
fn test_nilrt() {
|
||||
test_template(include_str!("os_release/nilrt"), Distribution::NILRT);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_coreos() {
|
||||
test_template(include_str!("os_release/coreos"), Distribution::FedoraImmutable);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_aurora() {
|
||||
test_template(include_str!("os_release/aurora"), Distribution::FedoraImmutable);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_bluefin() {
|
||||
test_template(include_str!("os_release/bluefin"), Distribution::FedoraImmutable);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_bazzite() {
|
||||
test_template(include_str!("os_release/bazzite"), Distribution::FedoraImmutable);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -203,7 +203,7 @@ pub fn update_xcodes(ctx: &ExecutionContext) -> Result<()> {
|
||||
.execute(&xcodes)
|
||||
.args([
|
||||
"uninstall",
|
||||
releases_new_installed.iter().next().cloned().unwrap_or_default(),
|
||||
releases_new_installed.iter().next().copied().unwrap_or_default(),
|
||||
])
|
||||
.status_checked();
|
||||
}
|
||||
@@ -216,12 +216,7 @@ pub fn update_xcodes(ctx: &ExecutionContext) -> Result<()> {
|
||||
pub fn process_xcodes_releases(releases_filtered: Vec<String>, should_ask: bool, ctx: &ExecutionContext) -> Result<()> {
|
||||
let xcodes = require("xcodes")?;
|
||||
|
||||
if releases_filtered
|
||||
.last()
|
||||
.map(|s| !s.contains("(Installed)"))
|
||||
.unwrap_or(true)
|
||||
&& !releases_filtered.is_empty()
|
||||
{
|
||||
if releases_filtered.last().map_or(true, |s| !s.contains("(Installed)")) && !releases_filtered.is_empty() {
|
||||
println!(
|
||||
"{} {}",
|
||||
t!("New Xcode release detected:"),
|
||||
|
||||
@@ -3,20 +3,51 @@ 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 = ["-current", "-beta"].iter().any(|&s| motd_content.contains(s));
|
||||
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 args = if is_current {
|
||||
vec!["/usr/sbin/sysupgrade", "-sn"]
|
||||
} else {
|
||||
vec!["/usr/sbin/syspatch"]
|
||||
};
|
||||
|
||||
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 +55,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(())
|
||||
}
|
||||
|
||||
23
src/steps/os/os_release/aurora
Normal file
23
src/steps/os/os_release/aurora
Normal file
@@ -0,0 +1,23 @@
|
||||
NAME="Aurora"
|
||||
VERSION="latest-41.20250210.4 (Kinoite)"
|
||||
RELEASE_TYPE=stable
|
||||
ID=aurora
|
||||
ID_LIKE="fedora"
|
||||
VERSION_ID=41
|
||||
VERSION_CODENAME=""
|
||||
PLATFORM_ID="platform:f41"
|
||||
PRETTY_NAME="Aurora (Version: latest-41.20250210.4 / FROM Fedora Kinoite 41)"
|
||||
ANSI_COLOR="0;38;2;60;110;180"
|
||||
LOGO=fedora-logo-icon
|
||||
CPE_NAME="cpe:/o:universal-blue:aurora:41"
|
||||
DEFAULT_HOSTNAME="aurora"
|
||||
HOME_URL="https://getaurora.dev/"
|
||||
DOCUMENTATION_URL="https://docs.getaurora.dev"
|
||||
SUPPORT_URL="https://github.com/ublue-os/aurora/issues/"
|
||||
BUG_REPORT_URL="https://github.com/ublue-os/aurora/issues/"
|
||||
SUPPORT_END=2025-12-15
|
||||
VARIANT="Kinoite"
|
||||
VARIANT_ID=aurora
|
||||
OSTREE_VERSION='latest-41.20250210.4'
|
||||
BUILD_ID="fc1570c"
|
||||
IMAGE_ID="aurora"
|
||||
25
src/steps/os/os_release/bazzite
Normal file
25
src/steps/os/os_release/bazzite
Normal file
@@ -0,0 +1,25 @@
|
||||
NAME="Bazzite"
|
||||
VERSION="41.20250208.0 (Kinoite)"
|
||||
RELEASE_TYPE=stable
|
||||
ID=bazzite
|
||||
ID_LIKE="fedora"
|
||||
VERSION_ID=41
|
||||
VERSION_CODENAME="Holographic"
|
||||
PLATFORM_ID="platform:f41"
|
||||
PRETTY_NAME="Bazzite 41 (FROM Fedora Kinoite)"
|
||||
ANSI_COLOR="0;38;2;138;43;226"
|
||||
LOGO=bazzite-logo-icon
|
||||
CPE_NAME="cpe:/o:universal-blue:bazzite:41"
|
||||
DEFAULT_HOSTNAME="bazzite"
|
||||
HOME_URL="https://bazzite.gg"
|
||||
DOCUMENTATION_URL="https://docs.bazzite.gg"
|
||||
SUPPORT_URL="https://discord.bazzite.gg"
|
||||
BUG_REPORT_URL="https://github.com/ublue-os/bazzite/issues/"
|
||||
SUPPORT_END=2025-12-15
|
||||
VARIANT="Kinoite"
|
||||
VARIANT_ID=bazzite-nvidia-open
|
||||
OSTREE_VERSION='41.20250208.0'
|
||||
BUILD_ID="Stable (F41.20250208)"
|
||||
BOOTLOADER_NAME="Bazzite Stable (F41.20250208)"
|
||||
BUILD_ID="Stable (F41.20250208)"
|
||||
BOOTLOADER_NAME="Bazzite Stable (F41.20250208)"
|
||||
24
src/steps/os/os_release/bluefin
Normal file
24
src/steps/os/os_release/bluefin
Normal file
@@ -0,0 +1,24 @@
|
||||
NAME="Bluefin"
|
||||
VERSION="41.20250216.1 (Silverblue)"
|
||||
RELEASE_TYPE=stable
|
||||
ID=bluefin
|
||||
ID_LIKE="fedora"
|
||||
VERSION_ID=41
|
||||
VERSION_CODENAME="Archaeopteryx"
|
||||
PLATFORM_ID="platform:f41"
|
||||
PRETTY_NAME="Bluefin (Version: 41.20250216.1 / FROM Fedora Silverblue 41)"
|
||||
ANSI_COLOR="0;38;2;60;110;180"
|
||||
LOGO=fedora-logo-icon
|
||||
CPE_NAME="cpe:/o:universal-blue:bluefin:41"
|
||||
DEFAULT_HOSTNAME="bluefin"
|
||||
HOME_URL="https://projectbluefin.io"
|
||||
DOCUMENTATION_URL="https://docs.projectbluefin.io"
|
||||
SUPPORT_URL="https://github.com/ublue-os/bluefin/issues/"
|
||||
BUG_REPORT_URL="https://github.com/ublue-os/bluefin/issues/"
|
||||
SUPPORT_END=2025-12-15
|
||||
VARIANT="Silverblue"
|
||||
VARIANT_ID=bluefin
|
||||
OSTREE_VERSION='41.20250216.1'
|
||||
BUILD_ID="185146a"
|
||||
IMAGE_ID="bluefin"
|
||||
IMAGE_VERSION="41.20250216.1"
|
||||
23
src/steps/os/os_release/coreos
Normal file
23
src/steps/os/os_release/coreos
Normal file
@@ -0,0 +1,23 @@
|
||||
NAME="Fedora Linux"
|
||||
VERSION="41.20250117.3.0 (CoreOS)"
|
||||
RELEASE_TYPE=stable
|
||||
ID=fedora
|
||||
VERSION_ID=41
|
||||
VERSION_CODENAME=""
|
||||
PLATFORM_ID="platform:f41"
|
||||
PRETTY_NAME="Fedora CoreOS 41.20250117.3.0 (uCore)"
|
||||
ANSI_COLOR="0;38;2;60;110;180"
|
||||
LOGO=fedora-logo-icon
|
||||
CPE_NAME="cpe:/o:fedoraproject:fedora:41"
|
||||
HOME_URL="https://getfedora.org/coreos/"
|
||||
DOCUMENTATION_URL="https://docs.fedoraproject.org/en-US/fedora-coreos/"
|
||||
SUPPORT_URL="https://github.com/coreos/fedora-coreos-tracker/"
|
||||
BUG_REPORT_URL="https://github.com/coreos/fedora-coreos-tracker/"
|
||||
REDHAT_BUGZILLA_PRODUCT="Fedora"
|
||||
REDHAT_BUGZILLA_PRODUCT_VERSION=41
|
||||
REDHAT_SUPPORT_PRODUCT="Fedora"
|
||||
REDHAT_SUPPORT_PRODUCT_VERSION=41
|
||||
SUPPORT_END=2025-12-15
|
||||
VARIANT="CoreOS"
|
||||
VARIANT_ID=coreos
|
||||
OSTREE_VERSION='41.20250117.3.0'
|
||||
@@ -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![".*"]
|
||||
@@ -583,8 +611,7 @@ fn nix_profile_dir(nix: &Path) -> Result<Option<PathBuf>> {
|
||||
if user_env
|
||||
.file_name()
|
||||
.and_then(|name| name.to_str())
|
||||
.map(|name| name.ends_with("user-environment"))
|
||||
.unwrap_or(false)
|
||||
.is_some_and(|name| name.ends_with("user-environment"))
|
||||
{
|
||||
Some(profile_dir)
|
||||
} else {
|
||||
@@ -609,10 +636,33 @@ pub fn run_asdf(ctx: &ExecutionContext) -> Result<()> {
|
||||
let asdf = require("asdf")?;
|
||||
|
||||
print_separator("asdf");
|
||||
ctx.run_type()
|
||||
.execute(&asdf)
|
||||
.arg("update")
|
||||
.status_checked_with_codes(&[42])?;
|
||||
|
||||
// asdf (>= 0.15.0) won't support the self-update command
|
||||
//
|
||||
// https://github.com/topgrade-rs/topgrade/issues/1007
|
||||
let version_output = Command::new(&asdf).arg("version").output_checked_utf8()?;
|
||||
// Example output
|
||||
//
|
||||
// ```
|
||||
// $ asdf version
|
||||
// v0.15.0-31e8c93
|
||||
//
|
||||
// ```
|
||||
let version_stdout = version_output.stdout.trim();
|
||||
// trim the starting 'v'
|
||||
let mut remaining = version_stdout.trim_start_matches('v');
|
||||
let idx = remaining
|
||||
.find('-')
|
||||
.expect("the output of `asdf version` changed, please file an issue to Topgrade");
|
||||
// remove the hash part
|
||||
remaining = &remaining[..idx];
|
||||
let version = Version::parse(remaining).expect("should be a valid version");
|
||||
if version < Version::new(0, 15, 0) {
|
||||
ctx.run_type()
|
||||
.execute(&asdf)
|
||||
.arg("update")
|
||||
.status_checked_with_codes(&[42])?;
|
||||
}
|
||||
|
||||
ctx.run_type()
|
||||
.execute(&asdf)
|
||||
@@ -625,12 +675,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<()> {
|
||||
@@ -666,9 +716,7 @@ pub fn run_pyenv(ctx: &ExecutionContext) -> Result<()> {
|
||||
let pyenv = require("pyenv")?;
|
||||
print_separator("pyenv");
|
||||
|
||||
let pyenv_dir = var("PYENV_ROOT")
|
||||
.map(PathBuf::from)
|
||||
.unwrap_or_else(|_| HOME_DIR.join(".pyenv"));
|
||||
let pyenv_dir = var("PYENV_ROOT").map_or_else(|_| HOME_DIR.join(".pyenv"), PathBuf::from);
|
||||
|
||||
if !pyenv_dir.exists() {
|
||||
return Err(SkipStep(t!("Pyenv is installed, but $PYENV_ROOT is not set correctly").to_string()).into());
|
||||
@@ -689,8 +737,7 @@ pub fn run_sdkman(ctx: &ExecutionContext) -> Result<()> {
|
||||
let bash = require("bash")?;
|
||||
|
||||
let sdkman_init_path = var("SDKMAN_DIR")
|
||||
.map(PathBuf::from)
|
||||
.unwrap_or_else(|_| HOME_DIR.join(".sdkman"))
|
||||
.map_or_else(|_| HOME_DIR.join(".sdkman"), PathBuf::from)
|
||||
.join("bin")
|
||||
.join("sdkman-init.sh")
|
||||
.require()
|
||||
@@ -699,8 +746,7 @@ pub fn run_sdkman(ctx: &ExecutionContext) -> Result<()> {
|
||||
print_separator("SDKMAN!");
|
||||
|
||||
let sdkman_config_path = var("SDKMAN_DIR")
|
||||
.map(PathBuf::from)
|
||||
.unwrap_or_else(|_| HOME_DIR.join(".sdkman"))
|
||||
.map_or_else(|_| HOME_DIR.join(".sdkman"), PathBuf::from)
|
||||
.join("etc")
|
||||
.join("config")
|
||||
.require()?;
|
||||
@@ -753,9 +799,7 @@ pub fn run_bun_packages(ctx: &ExecutionContext) -> Result<()> {
|
||||
|
||||
print_separator(t!("Bun Packages"));
|
||||
|
||||
let mut package_json: PathBuf = var("BUN_INSTALL")
|
||||
.map(PathBuf::from)
|
||||
.unwrap_or_else(|_| HOME_DIR.join(".bun"));
|
||||
let mut package_json: PathBuf = var("BUN_INSTALL").map_or_else(|_| HOME_DIR.join(".bun"), PathBuf::from);
|
||||
package_json.push("install/global/package.json");
|
||||
|
||||
if !package_json.exists() {
|
||||
|
||||
@@ -42,10 +42,12 @@ pub fn run_winget(ctx: &ExecutionContext) -> Result<()> {
|
||||
|
||||
print_separator("winget");
|
||||
|
||||
ctx.run_type()
|
||||
.execute(winget)
|
||||
.args(["upgrade", "--all"])
|
||||
.status_checked()
|
||||
let mut args = vec!["upgrade", "--all"];
|
||||
if ctx.config().winget_silent_install() {
|
||||
args.push("--silent");
|
||||
}
|
||||
|
||||
ctx.run_type().execute(winget).args(args).status_checked()
|
||||
}
|
||||
|
||||
pub fn run_scoop(ctx: &ExecutionContext) -> Result<()> {
|
||||
@@ -221,6 +223,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.
|
||||
|
||||
@@ -9,7 +9,7 @@ use rust_i18n::t;
|
||||
use crate::command::CommandExt;
|
||||
use crate::execution_context::ExecutionContext;
|
||||
use crate::terminal::{is_dumb, print_separator};
|
||||
use crate::utils::{require_option, which, PathExt};
|
||||
use crate::utils::{require_option, which};
|
||||
use crate::Step;
|
||||
|
||||
pub struct Powershell {
|
||||
@@ -30,7 +30,7 @@ impl Powershell {
|
||||
.args(["-NoProfile", "-Command", "Split-Path $profile"])
|
||||
.output_checked_utf8()
|
||||
.map(|output| PathBuf::from(output.stdout.trim()))
|
||||
.and_then(|p| p.require())
|
||||
.and_then(super::super::utils::PathExt::require)
|
||||
.ok()
|
||||
});
|
||||
|
||||
@@ -70,11 +70,11 @@ impl Powershell {
|
||||
let mut cmd = vec!["Update-Module"];
|
||||
|
||||
if ctx.config().verbose() {
|
||||
cmd.push("-Verbose")
|
||||
cmd.push("-Verbose");
|
||||
}
|
||||
|
||||
if ctx.config().yes(Step::Powershell) {
|
||||
cmd.push("-Force")
|
||||
cmd.push("-Force");
|
||||
}
|
||||
|
||||
println!("{}", t!("Updating modules..."));
|
||||
@@ -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(|_| ())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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"
|
||||
@@ -232,7 +232,7 @@ pub fn upgrade_vagrant_boxes(ctx: &ExecutionContext) -> Result<()> {
|
||||
}
|
||||
|
||||
if !found {
|
||||
println!("{}", t!("No outdated boxes"))
|
||||
println!("{}", t!("No outdated boxes"));
|
||||
} else {
|
||||
ctx.run_type()
|
||||
.execute(&vagrant)
|
||||
|
||||
@@ -128,7 +128,7 @@ impl Tmux {
|
||||
.output_checked_utf8()?
|
||||
.stdout
|
||||
.lines()
|
||||
.map(|l| l.parse())
|
||||
.map(str::parse)
|
||||
.collect::<Result<Vec<usize>, _>>()
|
||||
.context("Failed to compute tmux windows")
|
||||
}
|
||||
@@ -181,19 +181,16 @@ pub fn run_in_tmux(config: TmuxConfig) -> Result<()> {
|
||||
pub fn run_command(ctx: &ExecutionContext, window_name: &str, command: &str) -> Result<()> {
|
||||
let tmux = Tmux::new(ctx.config().tmux_config()?.args);
|
||||
|
||||
match ctx.get_tmux_session() {
|
||||
Some(session_name) => {
|
||||
let indices = tmux.window_indices(&session_name)?;
|
||||
let last_window = indices
|
||||
.iter()
|
||||
.last()
|
||||
.ok_or_else(|| eyre!("tmux session {session_name} has no windows"))?;
|
||||
tmux.new_window(&session_name, &format!("{last_window}"), command)?;
|
||||
}
|
||||
None => {
|
||||
let name = tmux.new_unique_session("topgrade", window_name, command)?;
|
||||
ctx.set_tmux_session(name);
|
||||
}
|
||||
if let Some(session_name) = ctx.get_tmux_session() {
|
||||
let indices = tmux.window_indices(&session_name)?;
|
||||
let last_window = indices
|
||||
.iter()
|
||||
.last()
|
||||
.ok_or_else(|| eyre!("tmux session {session_name} has no windows"))?;
|
||||
tmux.new_window(&session_name, &format!("{last_window}"), command)?;
|
||||
} else {
|
||||
let name = tmux.new_unique_session("topgrade", window_name, command)?;
|
||||
ctx.set_tmux_session(name);
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -65,7 +65,7 @@ fn upgrade(command: &mut Executor, ctx: &ExecutionContext) -> Result<()> {
|
||||
if !status.success() {
|
||||
return Err(TopgradeError::ProcessFailed(command.get_program(), status).into());
|
||||
} else {
|
||||
println!("{}", t!("Plugins upgraded"))
|
||||
println!("{}", t!("Plugins upgraded"));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -30,9 +30,7 @@ pub fn run_zr(ctx: &ExecutionContext) -> Result<()> {
|
||||
}
|
||||
|
||||
fn zdotdir() -> PathBuf {
|
||||
env::var("ZDOTDIR")
|
||||
.map(PathBuf::from)
|
||||
.unwrap_or_else(|_| HOME_DIR.clone())
|
||||
env::var("ZDOTDIR").map_or_else(|_| HOME_DIR.clone(), PathBuf::from)
|
||||
}
|
||||
|
||||
pub fn zshrc() -> PathBuf {
|
||||
@@ -66,8 +64,7 @@ pub fn run_antigen(ctx: &ExecutionContext) -> Result<()> {
|
||||
let zsh = require("zsh")?;
|
||||
let zshrc = zshrc().require()?;
|
||||
env::var("ADOTDIR")
|
||||
.map(PathBuf::from)
|
||||
.unwrap_or_else(|_| HOME_DIR.join("antigen.zsh"))
|
||||
.map_or_else(|_| HOME_DIR.join("antigen.zsh"), PathBuf::from)
|
||||
.require()?;
|
||||
|
||||
print_separator("antigen");
|
||||
@@ -83,8 +80,7 @@ pub fn run_zgenom(ctx: &ExecutionContext) -> Result<()> {
|
||||
let zsh = require("zsh")?;
|
||||
let zshrc = zshrc().require()?;
|
||||
env::var("ZGEN_SOURCE")
|
||||
.map(PathBuf::from)
|
||||
.unwrap_or_else(|_| HOME_DIR.join(".zgenom"))
|
||||
.map_or_else(|_| HOME_DIR.join(".zgenom"), PathBuf::from)
|
||||
.require()?;
|
||||
|
||||
print_separator("zgenom");
|
||||
@@ -101,8 +97,7 @@ pub fn run_zplug(ctx: &ExecutionContext) -> Result<()> {
|
||||
zshrc().require()?;
|
||||
|
||||
env::var("ZPLUG_HOME")
|
||||
.map(PathBuf::from)
|
||||
.unwrap_or_else(|_| HOME_DIR.join(".zplug"))
|
||||
.map_or_else(|_| HOME_DIR.join(".zplug"), PathBuf::from)
|
||||
.require()?;
|
||||
|
||||
print_separator("zplug");
|
||||
@@ -118,8 +113,7 @@ pub fn run_zinit(ctx: &ExecutionContext) -> Result<()> {
|
||||
let zshrc = zshrc().require()?;
|
||||
|
||||
env::var("ZINIT_HOME")
|
||||
.map(PathBuf::from)
|
||||
.unwrap_or_else(|_| XDG_DIRS.data_dir().join("zinit"))
|
||||
.map_or_else(|_| XDG_DIRS.data_dir().join("zinit"), PathBuf::from)
|
||||
.require()?;
|
||||
|
||||
print_separator("zinit");
|
||||
@@ -153,8 +147,7 @@ pub fn run_zim(ctx: &ExecutionContext) -> Result<()> {
|
||||
.output_checked_utf8()
|
||||
.map(|o| o.stdout)
|
||||
})
|
||||
.map(PathBuf::from)
|
||||
.unwrap_or_else(|_| HOME_DIR.join(".zim"))
|
||||
.map_or_else(|_| HOME_DIR.join(".zim"), PathBuf::from)
|
||||
.require()?;
|
||||
|
||||
print_separator("zim");
|
||||
|
||||
31
src/sudo.rs
31
src/sudo.rs
@@ -22,13 +22,28 @@ pub struct Sudo {
|
||||
}
|
||||
|
||||
impl Sudo {
|
||||
/// Get the `sudo` binary or the `gsudo` binary in the case of `gsudo`
|
||||
/// masquerading as the `sudo` binary.
|
||||
fn determine_sudo_variant(sudo_p: PathBuf) -> (PathBuf, SudoKind) {
|
||||
match which("gsudo") {
|
||||
Some(gsudo_p) => {
|
||||
match std::fs::canonicalize(&gsudo_p).unwrap() == std::fs::canonicalize(&sudo_p).unwrap() {
|
||||
true => (gsudo_p, SudoKind::Gsudo),
|
||||
false => (sudo_p, SudoKind::Sudo),
|
||||
}
|
||||
}
|
||||
None => (sudo_p, SudoKind::Sudo),
|
||||
}
|
||||
}
|
||||
|
||||
/// Get the `sudo` binary for this platform.
|
||||
pub fn detect() -> Option<Self> {
|
||||
which("doas")
|
||||
.map(|p| (p, SudoKind::Doas))
|
||||
.or_else(|| which("sudo").map(|p| (p, SudoKind::Sudo)))
|
||||
.or_else(|| which("sudo").map(Self::determine_sudo_variant))
|
||||
.or_else(|| which("gsudo").map(|p| (p, SudoKind::Gsudo)))
|
||||
.or_else(|| which("pkexec").map(|p| (p, SudoKind::Pkexec)))
|
||||
.or_else(|| which("run0").map(|p| (p, SudoKind::Run0)))
|
||||
.or_else(|| which("please").map(|p| (p, SudoKind::Please)))
|
||||
.map(|(path, kind)| Self { path, kind })
|
||||
}
|
||||
@@ -65,9 +80,11 @@ impl Sudo {
|
||||
cmd.arg("-v");
|
||||
}
|
||||
SudoKind::Gsudo => {
|
||||
// Shows current user, cache and console status.
|
||||
// `gsudo` doesn't have anything like `sudo -v` to cache credentials,
|
||||
// so we just execute a dummy `echo` command so we have something
|
||||
// unobtrusive to run.
|
||||
// See: https://gerardog.github.io/gsudo/docs/usage
|
||||
cmd.arg("status");
|
||||
cmd.arg("echo");
|
||||
}
|
||||
SudoKind::Pkexec => {
|
||||
// I don't think this does anything; `pkexec` usually asks for
|
||||
@@ -79,6 +96,13 @@ impl Sudo {
|
||||
// See: https://linux.die.net/man/1/pkexec
|
||||
cmd.arg("echo");
|
||||
}
|
||||
SudoKind::Run0 => {
|
||||
// `run0` uses polkit for authentication
|
||||
// and thus has the same issues as `pkexec`.
|
||||
//
|
||||
// See: https://www.freedesktop.org/software/systemd/man/devel/run0.html
|
||||
cmd.arg("echo");
|
||||
}
|
||||
SudoKind::Please => {
|
||||
// From `man please`
|
||||
// -w, --warm
|
||||
@@ -115,6 +139,7 @@ pub enum SudoKind {
|
||||
Sudo,
|
||||
Gsudo,
|
||||
Pkexec,
|
||||
Run0,
|
||||
Please,
|
||||
}
|
||||
|
||||
|
||||
@@ -52,9 +52,7 @@ impl Terminal {
|
||||
Self {
|
||||
width: term.size_checked().map(|(_, w)| w),
|
||||
term,
|
||||
prefix: env::var("TOPGRADE_PREFIX")
|
||||
.map(|prefix| format!("({prefix}) "))
|
||||
.unwrap_or_else(|_| String::new()),
|
||||
prefix: env::var("TOPGRADE_PREFIX").map_or_else(|_| String::new(), |prefix| format!("({prefix}) ")),
|
||||
set_title: true,
|
||||
display_time: true,
|
||||
desktop_notification: false,
|
||||
@@ -62,15 +60,15 @@ impl Terminal {
|
||||
}
|
||||
|
||||
fn set_desktop_notifications(&mut self, desktop_notifications: bool) {
|
||||
self.desktop_notification = desktop_notifications
|
||||
self.desktop_notification = desktop_notifications;
|
||||
}
|
||||
|
||||
fn set_title(&mut self, set_title: bool) {
|
||||
self.set_title = set_title
|
||||
self.set_title = set_title;
|
||||
}
|
||||
|
||||
fn display_time(&mut self, display_time: bool) {
|
||||
self.display_time = display_time
|
||||
self.display_time = display_time;
|
||||
}
|
||||
|
||||
fn notify_desktop<P: AsRef<str>>(&self, message: P, timeout: Option<Duration>) {
|
||||
@@ -223,8 +221,8 @@ impl Terminal {
|
||||
|
||||
let answer = loop {
|
||||
match self.term.read_key() {
|
||||
Ok(Key::Char('y')) | Ok(Key::Char('Y')) => break Ok(true),
|
||||
Ok(Key::Char('s')) | Ok(Key::Char('S')) => {
|
||||
Ok(Key::Char('y' | 'Y')) => break Ok(true),
|
||||
Ok(Key::Char('s' | 'S')) => {
|
||||
println!(
|
||||
"\n\n{}\n",
|
||||
t!("Dropping you to shell. Fix what you need and then exit the shell.")
|
||||
@@ -235,12 +233,12 @@ impl Terminal {
|
||||
break Ok(true);
|
||||
}
|
||||
}
|
||||
Ok(Key::Char('n')) | Ok(Key::Char('N')) | Ok(Key::Enter) => break Ok(false),
|
||||
Ok(Key::Char('n' | 'N') | Key::Enter) => break Ok(false),
|
||||
Err(e) => {
|
||||
error!("Error reading from terminal: {}", e);
|
||||
break Ok(false);
|
||||
}
|
||||
Ok(Key::Char('q')) | Ok(Key::Char('Q')) => {
|
||||
Ok(Key::Char('q' | 'Q')) => {
|
||||
return Err(io::Error::from(io::ErrorKind::Interrupted)).context("Quit from user input")
|
||||
}
|
||||
_ => (),
|
||||
@@ -268,26 +266,26 @@ pub fn should_retry(interrupted: bool, step_name: &str) -> eyre::Result<bool> {
|
||||
}
|
||||
|
||||
pub fn print_separator<P: AsRef<str>>(message: P) {
|
||||
TERMINAL.lock().unwrap().print_separator(message)
|
||||
TERMINAL.lock().unwrap().print_separator(message);
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
pub fn print_error<P: AsRef<str>, Q: AsRef<str>>(key: Q, message: P) {
|
||||
TERMINAL.lock().unwrap().print_error(key, message)
|
||||
TERMINAL.lock().unwrap().print_error(key, message);
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
pub fn print_warning<P: AsRef<str>>(message: P) {
|
||||
TERMINAL.lock().unwrap().print_warning(message)
|
||||
TERMINAL.lock().unwrap().print_warning(message);
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
pub fn print_info<P: AsRef<str>>(message: P) {
|
||||
TERMINAL.lock().unwrap().print_info(message)
|
||||
TERMINAL.lock().unwrap().print_info(message);
|
||||
}
|
||||
|
||||
pub fn print_result<P: AsRef<str>>(key: P, result: &StepResult) {
|
||||
TERMINAL.lock().unwrap().print_result(key, result)
|
||||
TERMINAL.lock().unwrap().print_result(key, result);
|
||||
}
|
||||
|
||||
/// Tells whether the terminal is dumb.
|
||||
@@ -316,7 +314,7 @@ pub fn prompt_yesno(question: &str) -> Result<bool, io::Error> {
|
||||
}
|
||||
|
||||
pub fn notify_desktop<P: AsRef<str>>(message: P, timeout: Option<Duration>) {
|
||||
TERMINAL.lock().unwrap().notify_desktop(message, timeout)
|
||||
TERMINAL.lock().unwrap().notify_desktop(message, timeout);
|
||||
}
|
||||
|
||||
pub fn display_time(display_time: bool) {
|
||||
|
||||
@@ -86,7 +86,7 @@ pub fn editor() -> Vec<String> {
|
||||
env::var("EDITOR")
|
||||
.unwrap_or_else(|_| String::from(if cfg!(windows) { "notepad" } else { "vi" }))
|
||||
.split_whitespace()
|
||||
.map(|s| s.to_owned())
|
||||
.map(std::borrow::ToOwned::to_owned)
|
||||
.collect()
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user