Compare commits
35 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 |
@@ -6,20 +6,21 @@ on:
|
|||||||
# types:
|
# types:
|
||||||
# - completed
|
# - completed
|
||||||
release:
|
release:
|
||||||
types: [ created ]
|
types: [created]
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
build:
|
build:
|
||||||
strategy:
|
strategy:
|
||||||
fail-fast: false
|
fail-fast: false
|
||||||
matrix:
|
matrix:
|
||||||
target: [
|
target:
|
||||||
"aarch64-unknown-linux-gnu",
|
[
|
||||||
"armv7-unknown-linux-gnueabihf",
|
"aarch64-unknown-linux-gnu",
|
||||||
"x86_64-unknown-linux-musl",
|
"armv7-unknown-linux-gnueabihf",
|
||||||
"aarch64-unknown-linux-musl",
|
"x86_64-unknown-linux-musl",
|
||||||
"x86_64-unknown-freebsd",
|
"aarch64-unknown-linux-musl",
|
||||||
]
|
"x86_64-unknown-freebsd",
|
||||||
|
]
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v4
|
- uses: actions/checkout@v4
|
||||||
@@ -29,9 +30,14 @@ jobs:
|
|||||||
if: ${{ matrix.target == 'aarch64-unknown-linux-gnu' }}
|
if: ${{ matrix.target == 'aarch64-unknown-linux-gnu' }}
|
||||||
shell: bash
|
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
|
- name: Install cargo-deb
|
||||||
run: cargo 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
|
shell: bash
|
||||||
|
|
||||||
- name: install targets
|
- name: install targets
|
||||||
@@ -75,14 +81,14 @@ jobs:
|
|||||||
rm -rf target/${{matrix.target}}
|
rm -rf target/${{matrix.target}}
|
||||||
cross build --release --target ${{matrix.target}}
|
cross build --release --target ${{matrix.target}}
|
||||||
cargo deb --target=${{matrix.target}} --no-build --no-strip
|
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
|
shell: bash
|
||||||
|
|
||||||
- name: Move Debian-based system package
|
- name: Move Debian-based system package
|
||||||
run: |
|
run: |
|
||||||
mkdir -p assets
|
mkdir -p assets
|
||||||
mv target/${{matrix.target}}/debian/*.deb 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
|
shell: bash
|
||||||
|
|
||||||
- name: Release
|
- name: Release
|
||||||
|
|||||||
0
BREAKINGCHANGES_dev.md
Normal file
0
BREAKINGCHANGES_dev.md
Normal file
300
Cargo.lock
generated
300
Cargo.lock
generated
@@ -1,6 +1,6 @@
|
|||||||
# This file is automatically @generated by Cargo.
|
# This file is automatically @generated by Cargo.
|
||||||
# It is not intended for manual editing.
|
# It is not intended for manual editing.
|
||||||
version = 3
|
version = 4
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "addr2line"
|
name = "addr2line"
|
||||||
@@ -202,7 +202,7 @@ checksum = "3b43422f69d8ff38f95f1b2bb76517c91589a924d1559a0e935d7c8ce0274c11"
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"syn 2.0.66",
|
"syn 2.0.99",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -237,7 +237,7 @@ checksum = "c6fa2087f2753a7da8cc1c0dbfcf89579dd57458e36769de5ac750b4671737ca"
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"syn 2.0.66",
|
"syn 2.0.99",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -355,9 +355,12 @@ checksum = "514de17de45fdb8dc022b1a7975556c53c86f9f0aa5f534b98977b171857c2c9"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "cc"
|
name = "cc"
|
||||||
version = "1.0.99"
|
version = "1.2.16"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "96c51067fd44124faa7f870b4b1c969379ad32b2ba805aa959430ceaa384f695"
|
checksum = "be714c154be609ec7f5dad223a33bf1482fff90472de28f7362806e6d4832b8c"
|
||||||
|
dependencies = [
|
||||||
|
"shlex",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "cfg-if"
|
name = "cfg-if"
|
||||||
@@ -388,7 +391,7 @@ dependencies = [
|
|||||||
"js-sys",
|
"js-sys",
|
||||||
"num-traits",
|
"num-traits",
|
||||||
"wasm-bindgen",
|
"wasm-bindgen",
|
||||||
"windows-targets 0.52.5",
|
"windows-targets 0.52.6",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -431,7 +434,7 @@ dependencies = [
|
|||||||
"heck",
|
"heck",
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"syn 2.0.66",
|
"syn 2.0.99",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -533,9 +536,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "core-foundation-sys"
|
name = "core-foundation-sys"
|
||||||
version = "0.8.6"
|
version = "0.8.7"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "06ea2b9bc92be3c2baa9334a323ebca2d6f074ff852cd1d7b11064035cd3868f"
|
checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "cpufeatures"
|
name = "cpufeatures"
|
||||||
@@ -620,7 +623,7 @@ checksum = "f46882e17999c6cc590af592290432be3bce0428cb0d5f8b6715e4dc7b383eb3"
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"syn 2.0.66",
|
"syn 2.0.99",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -658,7 +661,16 @@ version = "5.0.1"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "44c45a9d03d6676652bcb5e724c7e988de1acad23a711b5217ab9cbecbec2225"
|
checksum = "44c45a9d03d6676652bcb5e724c7e988de1acad23a711b5217ab9cbecbec2225"
|
||||||
dependencies = [
|
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]]
|
[[package]]
|
||||||
@@ -679,10 +691,22 @@ checksum = "520f05a5cbd335fae5a99ff7a6ab8627577660ee5cfd6a94a6a929b52ff0321c"
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"libc",
|
"libc",
|
||||||
"option-ext",
|
"option-ext",
|
||||||
"redox_users",
|
"redox_users 0.4.5",
|
||||||
"windows-sys 0.48.0",
|
"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]]
|
[[package]]
|
||||||
name = "dirs-sys-next"
|
name = "dirs-sys-next"
|
||||||
version = "0.1.2"
|
version = "0.1.2"
|
||||||
@@ -690,7 +714,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||||||
checksum = "4ebda144c4fe02d1f7ea1a7d9641b6fc6b580adcfa024ae48797ecdeb6825b4d"
|
checksum = "4ebda144c4fe02d1f7ea1a7d9641b6fc6b580adcfa024ae48797ecdeb6825b4d"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"libc",
|
"libc",
|
||||||
"redox_users",
|
"redox_users 0.4.5",
|
||||||
"winapi",
|
"winapi",
|
||||||
]
|
]
|
||||||
|
|
||||||
@@ -702,7 +726,7 @@ checksum = "487585f4d0c6655fe74905e2504d8ad6908e4db67f744eb140876906c2f3175d"
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"syn 2.0.66",
|
"syn 2.0.99",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -775,7 +799,7 @@ checksum = "de0d48a183585823424a4ce1aa132d174a6a81bd540895822eb4c8373a8e49e8"
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"syn 2.0.66",
|
"syn 2.0.99",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -963,7 +987,7 @@ checksum = "87750cf4b7a4c0625b1529e4c543c2182106e4dedc60a2a6455e00d212c489ac"
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"syn 2.0.66",
|
"syn 2.0.99",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -1326,7 +1350,7 @@ checksum = "1ec89e9337638ecdc08744df490b221a7399bf8d164eb52a665454e60e075ad6"
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"syn 2.0.66",
|
"syn 2.0.99",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -1423,6 +1447,17 @@ version = "1.0.11"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "49f1f14873335454500d59611f1cf4a4b0f786f9ac11f4312a78e4cf2566695b"
|
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]]
|
[[package]]
|
||||||
name = "js-sys"
|
name = "js-sys"
|
||||||
version = "0.3.69"
|
version = "0.3.69"
|
||||||
@@ -1432,6 +1467,12 @@ dependencies = [
|
|||||||
"wasm-bindgen",
|
"wasm-bindgen",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "json"
|
||||||
|
version = "0.12.4"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "078e285eafdfb6c4b434e0d31e8cfcb5115b651496faca5749b88fafd4f23bfd"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "lazy_static"
|
name = "lazy_static"
|
||||||
version = "1.4.0"
|
version = "1.4.0"
|
||||||
@@ -1440,9 +1481,9 @@ checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "libc"
|
name = "libc"
|
||||||
version = "0.2.155"
|
version = "0.2.170"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "97b3888a4aecf77e811145cadf6eef5901f4782c53886191b2f693f24761847c"
|
checksum = "875b3680cb2f8f71bdcf9a30f38d48282f5d3c95cbf9b3fa57269bb5d5c06828"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "libredox"
|
name = "libredox"
|
||||||
@@ -1619,6 +1660,15 @@ dependencies = [
|
|||||||
"zbus",
|
"zbus",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "ntapi"
|
||||||
|
version = "0.4.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "e8a3895c6391c39d7fe7ebc444a87eb2991b2a0bc718fdabd071eec617fc68e4"
|
||||||
|
dependencies = [
|
||||||
|
"winapi",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "nu-ansi-term"
|
name = "nu-ansi-term"
|
||||||
version = "0.46.0"
|
version = "0.46.0"
|
||||||
@@ -1757,7 +1807,7 @@ dependencies = [
|
|||||||
"bitflags 1.3.2",
|
"bitflags 1.3.2",
|
||||||
"byteorder",
|
"byteorder",
|
||||||
"chrono",
|
"chrono",
|
||||||
"thiserror",
|
"thiserror 1.0.61",
|
||||||
"widestring",
|
"widestring",
|
||||||
]
|
]
|
||||||
|
|
||||||
@@ -1784,7 +1834,7 @@ checksum = "2f38a4412a78282e09a2cf38d195ea5420d15ba0602cb375210efbc877243965"
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"syn 2.0.66",
|
"syn 2.0.99",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -1888,9 +1938,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "proc-macro2"
|
name = "proc-macro2"
|
||||||
version = "1.0.85"
|
version = "1.0.94"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "22244ce15aa966053a896d1accb3a6e68469b97c7f33f284b99f0d576879fc23"
|
checksum = "a31971752e70b8b2686d7e46ec17fb38dad4051d94024c88df49b667caea9c84"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"unicode-ident",
|
"unicode-ident",
|
||||||
]
|
]
|
||||||
@@ -1952,6 +2002,26 @@ dependencies = [
|
|||||||
"getrandom",
|
"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]]
|
[[package]]
|
||||||
name = "redox_syscall"
|
name = "redox_syscall"
|
||||||
version = "0.4.1"
|
version = "0.4.1"
|
||||||
@@ -1969,7 +2039,18 @@ checksum = "bd283d9651eeda4b2a83a43c1c91b266c40fd76ecd39a50a8c630ae69dc72891"
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"getrandom",
|
"getrandom",
|
||||||
"libredox",
|
"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]]
|
[[package]]
|
||||||
@@ -2069,15 +2150,14 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "ring"
|
name = "ring"
|
||||||
version = "0.17.8"
|
version = "0.17.13"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "c17fa4cb658e3583423e915b9f3acc01cceaee1860e33d59ebae66adc3a2dc0d"
|
checksum = "70ac5d832aa16abd7d1def883a8545280c20a60f523a370aa3a9617c2b8550ee"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"cc",
|
"cc",
|
||||||
"cfg-if",
|
"cfg-if",
|
||||||
"getrandom",
|
"getrandom",
|
||||||
"libc",
|
"libc",
|
||||||
"spin",
|
|
||||||
"untrusted",
|
"untrusted",
|
||||||
"windows-sys 0.52.0",
|
"windows-sys 0.52.0",
|
||||||
]
|
]
|
||||||
@@ -2116,7 +2196,7 @@ dependencies = [
|
|||||||
"serde",
|
"serde",
|
||||||
"serde_json",
|
"serde_json",
|
||||||
"serde_yaml",
|
"serde_yaml",
|
||||||
"syn 2.0.66",
|
"syn 2.0.99",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -2298,7 +2378,7 @@ checksum = "500cbc0ebeb6f46627f50f3f5811ccf6bf00643be300b4c3eabc0ef55dc5b5ba"
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"syn 2.0.66",
|
"syn 2.0.99",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -2320,7 +2400,7 @@ checksum = "6c64451ba24fc7a6a2d60fc75dd9c83c90903b19028d4eff35e88fc1e86564e9"
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"syn 2.0.66",
|
"syn 2.0.99",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -2399,9 +2479,15 @@ version = "3.1.0"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "da03fa3b94cc19e3ebfc88c4229c49d8f08cdbd1228870a45f0ffdf84988e14b"
|
checksum = "da03fa3b94cc19e3ebfc88c4229c49d8f08cdbd1228870a45f0ffdf84988e14b"
|
||||||
dependencies = [
|
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]]
|
[[package]]
|
||||||
name = "signal-hook-registry"
|
name = "signal-hook-registry"
|
||||||
version = "1.4.2"
|
version = "1.4.2"
|
||||||
@@ -2446,12 +2532,6 @@ dependencies = [
|
|||||||
"windows-sys 0.52.0",
|
"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]]
|
[[package]]
|
||||||
name = "spki"
|
name = "spki"
|
||||||
version = "0.7.3"
|
version = "0.7.3"
|
||||||
@@ -2499,7 +2579,7 @@ dependencies = [
|
|||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"rustversion",
|
"rustversion",
|
||||||
"syn 2.0.66",
|
"syn 2.0.99",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -2521,9 +2601,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "syn"
|
name = "syn"
|
||||||
version = "2.0.66"
|
version = "2.0.99"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "c42f3f41a2de00b01c0aaad383c5a45241efc8b2d1eda5661812fda5f3cdcff5"
|
checksum = "e02e925281e18ffd9d640e234264753c43edc62d64b2d4cf898f1bc5e75f3fc2"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
@@ -2544,7 +2624,7 @@ checksum = "c8af7666ab7b6390ab78131fb5b0fce11d6b7a6951602017c35fa82800708971"
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"syn 2.0.66",
|
"syn 2.0.99",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -2556,6 +2636,20 @@ dependencies = [
|
|||||||
"libc",
|
"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]]
|
[[package]]
|
||||||
name = "tar"
|
name = "tar"
|
||||||
version = "0.4.41"
|
version = "0.4.41"
|
||||||
@@ -2596,7 +2690,16 @@ version = "1.0.61"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "c546c80d6be4bc6a00c0f01730c08df82eaa7a7a61f11d656526506112cc1709"
|
checksum = "c546c80d6be4bc6a00c0f01730c08df82eaa7a7a61f11d656526506112cc1709"
|
||||||
dependencies = [
|
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]]
|
[[package]]
|
||||||
@@ -2607,7 +2710,18 @@ checksum = "46c3384250002a6d5af4d114f2845d37b57521033f30d5c3f46c4d70e1197533"
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"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]]
|
[[package]]
|
||||||
@@ -2770,7 +2884,7 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "topgrade"
|
name = "topgrade"
|
||||||
version = "16.0.2"
|
version = "16.0.3"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"cfg-if",
|
"cfg-if",
|
||||||
"chrono",
|
"chrono",
|
||||||
@@ -2783,6 +2897,7 @@ dependencies = [
|
|||||||
"futures",
|
"futures",
|
||||||
"glob",
|
"glob",
|
||||||
"home",
|
"home",
|
||||||
|
"jetbrains-toolbox-updater",
|
||||||
"lazy_static",
|
"lazy_static",
|
||||||
"merge",
|
"merge",
|
||||||
"nix 0.29.0",
|
"nix 0.29.0",
|
||||||
@@ -2801,7 +2916,7 @@ dependencies = [
|
|||||||
"strum",
|
"strum",
|
||||||
"sys-locale",
|
"sys-locale",
|
||||||
"tempfile",
|
"tempfile",
|
||||||
"thiserror",
|
"thiserror 1.0.61",
|
||||||
"tokio",
|
"tokio",
|
||||||
"toml 0.8.14",
|
"toml 0.8.14",
|
||||||
"tracing",
|
"tracing",
|
||||||
@@ -2859,7 +2974,7 @@ checksum = "34704c8d6ebcbc939824180af020566b01a7c01f80641264eba0999f6c2b6be7"
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"syn 2.0.66",
|
"syn 2.0.99",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -3063,7 +3178,7 @@ dependencies = [
|
|||||||
"once_cell",
|
"once_cell",
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"syn 2.0.66",
|
"syn 2.0.99",
|
||||||
"wasm-bindgen-shared",
|
"wasm-bindgen-shared",
|
||||||
]
|
]
|
||||||
|
|
||||||
@@ -3097,7 +3212,7 @@ checksum = "e94f17b526d0a461a191c78ea52bbce64071ed5c04c9ffe424dcb38f74171bb7"
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"syn 2.0.66",
|
"syn 2.0.99",
|
||||||
"wasm-bindgen-backend",
|
"wasm-bindgen-backend",
|
||||||
"wasm-bindgen-shared",
|
"wasm-bindgen-shared",
|
||||||
]
|
]
|
||||||
@@ -3189,7 +3304,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||||||
checksum = "1de69df01bdf1ead2f4ac895dc77c9351aefff65b2f3db429a343f9cbf05e132"
|
checksum = "1de69df01bdf1ead2f4ac895dc77c9351aefff65b2f3db429a343f9cbf05e132"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"windows-core 0.56.0",
|
"windows-core 0.56.0",
|
||||||
"windows-targets 0.52.5",
|
"windows-targets 0.52.6",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -3198,7 +3313,7 @@ version = "0.52.0"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "33ab640c8d7e35bf8ba19b884ba838ceb4fba93a4e8c65a9059d08afcfc683d9"
|
checksum = "33ab640c8d7e35bf8ba19b884ba838ceb4fba93a4e8c65a9059d08afcfc683d9"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"windows-targets 0.52.5",
|
"windows-targets 0.52.6",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -3210,7 +3325,7 @@ dependencies = [
|
|||||||
"windows-implement",
|
"windows-implement",
|
||||||
"windows-interface",
|
"windows-interface",
|
||||||
"windows-result",
|
"windows-result",
|
||||||
"windows-targets 0.52.5",
|
"windows-targets 0.52.6",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -3221,7 +3336,7 @@ checksum = "f6fc35f58ecd95a9b71c4f2329b911016e6bec66b3f2e6a4aad86bd2e99e2f9b"
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"syn 2.0.66",
|
"syn 2.0.99",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -3232,7 +3347,7 @@ checksum = "08990546bf4edef8f431fa6326e032865f27138718c587dc21bc0265bbcb57cc"
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"syn 2.0.66",
|
"syn 2.0.99",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -3241,7 +3356,7 @@ version = "0.1.2"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "5e383302e8ec8515204254685643de10811af0ed97ea37210dc26fb0032647f8"
|
checksum = "5e383302e8ec8515204254685643de10811af0ed97ea37210dc26fb0032647f8"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"windows-targets 0.52.5",
|
"windows-targets 0.52.6",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -3259,7 +3374,16 @@ version = "0.52.0"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d"
|
checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d"
|
||||||
dependencies = [
|
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]]
|
[[package]]
|
||||||
@@ -3279,18 +3403,18 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "windows-targets"
|
name = "windows-targets"
|
||||||
version = "0.52.5"
|
version = "0.52.6"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "6f0713a46559409d202e70e28227288446bf7841d3211583a4b53e3f6d96e7eb"
|
checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"windows_aarch64_gnullvm 0.52.5",
|
"windows_aarch64_gnullvm 0.52.6",
|
||||||
"windows_aarch64_msvc 0.52.5",
|
"windows_aarch64_msvc 0.52.6",
|
||||||
"windows_i686_gnu 0.52.5",
|
"windows_i686_gnu 0.52.6",
|
||||||
"windows_i686_gnullvm",
|
"windows_i686_gnullvm",
|
||||||
"windows_i686_msvc 0.52.5",
|
"windows_i686_msvc 0.52.6",
|
||||||
"windows_x86_64_gnu 0.52.5",
|
"windows_x86_64_gnu 0.52.6",
|
||||||
"windows_x86_64_gnullvm 0.52.5",
|
"windows_x86_64_gnullvm 0.52.6",
|
||||||
"windows_x86_64_msvc 0.52.5",
|
"windows_x86_64_msvc 0.52.6",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -3299,7 +3423,7 @@ version = "0.1.1"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "6998aa457c9ba8ff2fb9f13e9d2a930dabcea28f1d0ab94d687d8b3654844515"
|
checksum = "6998aa457c9ba8ff2fb9f13e9d2a930dabcea28f1d0ab94d687d8b3654844515"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"windows-targets 0.52.5",
|
"windows-targets 0.52.6",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -3310,9 +3434,9 @@ checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "windows_aarch64_gnullvm"
|
name = "windows_aarch64_gnullvm"
|
||||||
version = "0.52.5"
|
version = "0.52.6"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "7088eed71e8b8dda258ecc8bac5fb1153c5cffaf2578fc8ff5d61e23578d3263"
|
checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "windows_aarch64_msvc"
|
name = "windows_aarch64_msvc"
|
||||||
@@ -3322,9 +3446,9 @@ checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "windows_aarch64_msvc"
|
name = "windows_aarch64_msvc"
|
||||||
version = "0.52.5"
|
version = "0.52.6"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "9985fd1504e250c615ca5f281c3f7a6da76213ebd5ccc9561496568a2752afb6"
|
checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "windows_i686_gnu"
|
name = "windows_i686_gnu"
|
||||||
@@ -3334,15 +3458,15 @@ checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "windows_i686_gnu"
|
name = "windows_i686_gnu"
|
||||||
version = "0.52.5"
|
version = "0.52.6"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "88ba073cf16d5372720ec942a8ccbf61626074c6d4dd2e745299726ce8b89670"
|
checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "windows_i686_gnullvm"
|
name = "windows_i686_gnullvm"
|
||||||
version = "0.52.5"
|
version = "0.52.6"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "87f4261229030a858f36b459e748ae97545d6f1ec60e5e0d6a3d32e0dc232ee9"
|
checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "windows_i686_msvc"
|
name = "windows_i686_msvc"
|
||||||
@@ -3352,9 +3476,9 @@ checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "windows_i686_msvc"
|
name = "windows_i686_msvc"
|
||||||
version = "0.52.5"
|
version = "0.52.6"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "db3c2bf3d13d5b658be73463284eaf12830ac9a26a90c717b7f771dfe97487bf"
|
checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "windows_x86_64_gnu"
|
name = "windows_x86_64_gnu"
|
||||||
@@ -3364,9 +3488,9 @@ checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "windows_x86_64_gnu"
|
name = "windows_x86_64_gnu"
|
||||||
version = "0.52.5"
|
version = "0.52.6"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "4e4246f76bdeff09eb48875a0fd3e2af6aada79d409d33011886d3e1581517d9"
|
checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "windows_x86_64_gnullvm"
|
name = "windows_x86_64_gnullvm"
|
||||||
@@ -3376,9 +3500,9 @@ checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "windows_x86_64_gnullvm"
|
name = "windows_x86_64_gnullvm"
|
||||||
version = "0.52.5"
|
version = "0.52.6"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "852298e482cd67c356ddd9570386e2862b5673c85bd5f88df9ab6802b334c596"
|
checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "windows_x86_64_msvc"
|
name = "windows_x86_64_msvc"
|
||||||
@@ -3388,9 +3512,9 @@ checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "windows_x86_64_msvc"
|
name = "windows_x86_64_msvc"
|
||||||
version = "0.52.5"
|
version = "0.52.6"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "bec47e5bfd1bff0eeaf6d8b485cc1074891a197ab4225d504cb7a1ab88b02bf0"
|
checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "winnow"
|
name = "winnow"
|
||||||
@@ -3488,7 +3612,7 @@ checksum = "28cc31741b18cb6f1d5ff12f5b7523e3d6eb0852bbbad19d73905511d9849b95"
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"syn 2.0.66",
|
"syn 2.0.99",
|
||||||
"synstructure",
|
"synstructure",
|
||||||
]
|
]
|
||||||
|
|
||||||
@@ -3539,7 +3663,7 @@ dependencies = [
|
|||||||
"proc-macro-crate",
|
"proc-macro-crate",
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"syn 2.0.66",
|
"syn 2.0.99",
|
||||||
"zvariant_utils",
|
"zvariant_utils",
|
||||||
]
|
]
|
||||||
|
|
||||||
@@ -3571,7 +3695,7 @@ checksum = "0ea7b4a3637ea8669cedf0f1fd5c286a17f3de97b8dd5a70a6c167a1730e63a5"
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"syn 2.0.66",
|
"syn 2.0.99",
|
||||||
"synstructure",
|
"synstructure",
|
||||||
]
|
]
|
||||||
|
|
||||||
@@ -3600,7 +3724,7 @@ checksum = "6eafa6dfb17584ea3e2bd6e76e0cc15ad7af12b09abdd1ca55961bed9b1063c6"
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"syn 2.0.66",
|
"syn 2.0.99",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -3624,7 +3748,7 @@ checksum = "2ba5aa1827d6b1a35a29b3413ec69ce5f796e4d897e3e5b38f461bef41d225ea"
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"base64 0.21.7",
|
"base64 0.21.7",
|
||||||
"ed25519-dalek",
|
"ed25519-dalek",
|
||||||
"thiserror",
|
"thiserror 1.0.61",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -3649,7 +3773,7 @@ dependencies = [
|
|||||||
"proc-macro-crate",
|
"proc-macro-crate",
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"syn 2.0.66",
|
"syn 2.0.99",
|
||||||
"zvariant_utils",
|
"zvariant_utils",
|
||||||
]
|
]
|
||||||
|
|
||||||
@@ -3661,5 +3785,5 @@ checksum = "fc242db087efc22bd9ade7aa7809e4ba828132edc312871584a6b4391bdf8786"
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"syn 2.0.66",
|
"syn 2.0.99",
|
||||||
]
|
]
|
||||||
|
|||||||
@@ -5,8 +5,8 @@ categories = ["os"]
|
|||||||
keywords = ["upgrade", "update"]
|
keywords = ["upgrade", "update"]
|
||||||
license = "GPL-3.0"
|
license = "GPL-3.0"
|
||||||
repository = "https://github.com/topgrade-rs/topgrade"
|
repository = "https://github.com/topgrade-rs/topgrade"
|
||||||
rust-version = "1.76.0"
|
rust-version = "1.84.1"
|
||||||
version = "16.0.2"
|
version = "16.0.3"
|
||||||
authors = ["Roey Darwish Dror <roey.ghost@gmail.com>", "Thomas Schönauer <t.schoenauer@hgs-wt.at>"]
|
authors = ["Roey Darwish Dror <roey.ghost@gmail.com>", "Thomas Schönauer <t.schoenauer@hgs-wt.at>"]
|
||||||
exclude = ["doc/screenshot.gif", "BREAKINGCHANGES_dev.md"]
|
exclude = ["doc/screenshot.gif", "BREAKINGCHANGES_dev.md"]
|
||||||
edition = "2021"
|
edition = "2021"
|
||||||
@@ -54,6 +54,7 @@ notify-rust = "~4.11"
|
|||||||
wildmatch = "2.3.0"
|
wildmatch = "2.3.0"
|
||||||
rust-i18n = "3.0.1"
|
rust-i18n = "3.0.1"
|
||||||
sys-locale = "0.3.1"
|
sys-locale = "0.3.1"
|
||||||
|
jetbrains-toolbox-updater = "1.1.0"
|
||||||
|
|
||||||
[package.metadata.generate-rpm]
|
[package.metadata.generate-rpm]
|
||||||
assets = [{ source = "target/release/topgrade", dest = "/usr/bin/topgrade" }]
|
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/)
|
- macOS: [Homebrew](https://formulae.brew.sh/formula/topgrade) or [MacPorts](https://ports.macports.org/port/topgrade/)
|
||||||
- Windows: [Chocolatey][choco], [Scoop][scoop] or [Winget][winget]
|
- Windows: [Chocolatey][choco], [Scoop][scoop] or [Winget][winget]
|
||||||
- PyPi: [pip](https://pypi.org/project/topgrade/)
|
- PyPi: [pip](https://pypi.org/project/topgrade/)
|
||||||
|
- Fedora: [Copr](https://copr.fedorainfracloud.org/coprs/lilay/topgrade/)
|
||||||
|
|
||||||
[choco]: https://community.chocolatey.org/packages/topgrade
|
[choco]: https://community.chocolatey.org/packages/topgrade
|
||||||
[scoop]: https://scoop.sh/#/apps?q=topgrade
|
[scoop]: https://scoop.sh/#/apps?q=topgrade
|
||||||
|
|||||||
@@ -103,8 +103,8 @@
|
|||||||
# enable_pipupgrade = true ###disabled by default
|
# enable_pipupgrade = true ###disabled by default
|
||||||
# pipupgrade_arguments = "-y -u --pip-path pip" ###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
|
# For the poetry step, by default, Topgrade skips its update if poetry is not
|
||||||
# installed with the official script. This configuration entry forces Topgrade
|
# installed with the official script. This configuration entry forces Topgrade
|
||||||
# to run the update in this case.
|
# to run the update in this case.
|
||||||
#
|
#
|
||||||
# (default: false)
|
# (default: false)
|
||||||
@@ -219,6 +219,10 @@
|
|||||||
|
|
||||||
# wsl_update_use_web_download = true
|
# 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
|
# 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
|
# to upgrade it. Use this only if you installed Topgrade by using a package
|
||||||
# manager such as Scoop or Cargo
|
# manager such as Scoop or Cargo
|
||||||
@@ -290,3 +294,34 @@
|
|||||||
# in the startup file, which might cause the update run to fail.
|
# in the startup file, which might cause the update run to fail.
|
||||||
# (default: true)
|
# (default: true)
|
||||||
# startup_file = 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 = ""
|
||||||
|
|||||||
503
locales/app.yml
503
locales/app.yml
File diff suppressed because it is too large
Load Diff
@@ -1,2 +1,2 @@
|
|||||||
[toolchain]
|
[toolchain]
|
||||||
channel = "1.76.0"
|
channel = "1.84.1"
|
||||||
|
|||||||
@@ -45,13 +45,13 @@ impl TryFrom<&Output> for Utf8Output {
|
|||||||
type Error = eyre::Error;
|
type Error = eyre::Error;
|
||||||
|
|
||||||
fn try_from(Output { status, stdout, stderr }: &Output) -> Result<Self, Self::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!(
|
eyre!(
|
||||||
"Stdout contained invalid UTF-8: {}",
|
"Stdout contained invalid UTF-8: {}",
|
||||||
String::from_utf8_lossy(err.as_bytes())
|
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!(
|
eyre!(
|
||||||
"Stderr contained invalid UTF-8: {}",
|
"Stderr contained invalid UTF-8: {}",
|
||||||
String::from_utf8_lossy(err.as_bytes())
|
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
|
/// Like [`Command::spawn`], but gives a nice error message if the command fails to
|
||||||
/// execute.
|
/// execute.
|
||||||
#[track_caller]
|
#[track_caller]
|
||||||
|
#[allow(dead_code)]
|
||||||
fn spawn_checked(&mut self) -> eyre::Result<Self::Child>;
|
fn spawn_checked(&mut self) -> eyre::Result<Self::Child>;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -69,6 +69,7 @@ pub enum Step {
|
|||||||
Chezmoi,
|
Chezmoi,
|
||||||
Chocolatey,
|
Chocolatey,
|
||||||
Choosenim,
|
Choosenim,
|
||||||
|
CinnamonSpices,
|
||||||
ClamAvDb,
|
ClamAvDb,
|
||||||
Composer,
|
Composer,
|
||||||
Conda,
|
Conda,
|
||||||
@@ -97,6 +98,7 @@ pub enum Step {
|
|||||||
Haxelib,
|
Haxelib,
|
||||||
Helm,
|
Helm,
|
||||||
HomeManager,
|
HomeManager,
|
||||||
|
JetBrainsToolbox,
|
||||||
Jetpack,
|
Jetpack,
|
||||||
Julia,
|
Julia,
|
||||||
Juliaup,
|
Juliaup,
|
||||||
@@ -125,6 +127,7 @@ pub enum Step {
|
|||||||
PipReviewLocal,
|
PipReviewLocal,
|
||||||
Pipupgrade,
|
Pipupgrade,
|
||||||
Pipx,
|
Pipx,
|
||||||
|
Pipxu,
|
||||||
Pixi,
|
Pixi,
|
||||||
Pkg,
|
Pkg,
|
||||||
Pkgin,
|
Pkgin,
|
||||||
@@ -163,6 +166,7 @@ pub enum Step {
|
|||||||
Vim,
|
Vim,
|
||||||
VoltaPackages,
|
VoltaPackages,
|
||||||
Vscode,
|
Vscode,
|
||||||
|
Vscodium,
|
||||||
Waydroid,
|
Waydroid,
|
||||||
Winget,
|
Winget,
|
||||||
Wsl,
|
Wsl,
|
||||||
@@ -170,6 +174,7 @@ pub enum Step {
|
|||||||
Xcodes,
|
Xcodes,
|
||||||
Yadm,
|
Yadm,
|
||||||
Yarn,
|
Yarn,
|
||||||
|
Zigup,
|
||||||
Zvm,
|
Zvm,
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -220,6 +225,7 @@ pub struct Windows {
|
|||||||
open_remotes_in_new_terminal: Option<bool>,
|
open_remotes_in_new_terminal: Option<bool>,
|
||||||
wsl_update_pre_release: Option<bool>,
|
wsl_update_pre_release: Option<bool>,
|
||||||
wsl_update_use_web_download: Option<bool>,
|
wsl_update_use_web_download: Option<bool>,
|
||||||
|
winget_silent_install: Option<bool>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Deserialize, Default, Debug, Merge)]
|
#[derive(Deserialize, Default, Debug, Merge)]
|
||||||
@@ -460,6 +466,21 @@ pub struct JuliaConfig {
|
|||||||
startup_file: Option<bool>,
|
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)]
|
#[derive(Deserialize, Default, Debug, Merge)]
|
||||||
#[serde(deny_unknown_fields)]
|
#[serde(deny_unknown_fields)]
|
||||||
/// Configuration file
|
/// Configuration file
|
||||||
@@ -529,6 +550,12 @@ pub struct ConfigFile {
|
|||||||
|
|
||||||
#[merge(strategy = crate::utils::merge_strategies::inner_merge_opt)]
|
#[merge(strategy = crate::utils::merge_strategies::inner_merge_opt)]
|
||||||
julia: Option<JuliaConfig>,
|
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 {
|
fn config_directory() -> PathBuf {
|
||||||
@@ -560,7 +587,7 @@ impl ConfigFile {
|
|||||||
];
|
];
|
||||||
|
|
||||||
// Search for the main config file
|
// Search for the main config file
|
||||||
for path in possible_config_paths.iter() {
|
for path in &possible_config_paths {
|
||||||
if path.exists() {
|
if path.exists() {
|
||||||
debug!("Configuration at {}", path.display());
|
debug!("Configuration at {}", path.display());
|
||||||
res.0.clone_from(path);
|
res.0.clone_from(path);
|
||||||
@@ -824,7 +851,7 @@ pub struct CommandLineArgs {
|
|||||||
|
|
||||||
/// Tracing filter directives.
|
/// 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)]
|
#[arg(long, default_value = DEFAULT_LOG_LEVEL)]
|
||||||
pub log_filter: String,
|
pub log_filter: String,
|
||||||
|
|
||||||
@@ -1474,8 +1501,7 @@ impl Config {
|
|||||||
.misc
|
.misc
|
||||||
.as_ref()
|
.as_ref()
|
||||||
.and_then(|misc| misc.ignore_failures.as_ref())
|
.and_then(|misc| misc.ignore_failures.as_ref())
|
||||||
.map(|v| v.contains(&step))
|
.is_some_and(|v| v.contains(&step))
|
||||||
.unwrap_or(false)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn use_predefined_git_repos(&self) -> bool {
|
pub fn use_predefined_git_repos(&self) -> bool {
|
||||||
@@ -1525,6 +1551,14 @@ impl Config {
|
|||||||
.unwrap_or(false)
|
.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> {
|
pub fn sudo_command(&self) -> Option<SudoKind> {
|
||||||
self.config_file.misc.as_ref().and_then(|misc| misc.sudo_command)
|
self.config_file.misc.as_ref().and_then(|misc| misc.sudo_command)
|
||||||
}
|
}
|
||||||
@@ -1667,6 +1701,47 @@ impl Config {
|
|||||||
.and_then(|julia| julia.startup_file)
|
.and_then(|julia| julia.startup_file)
|
||||||
.unwrap_or(true)
|
.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)]
|
#[cfg(test)]
|
||||||
@@ -1693,40 +1768,40 @@ mod test {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_should_execute_remote_different_hostname() {
|
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]
|
#[test]
|
||||||
fn test_should_execute_remote_different_hostname_with_user() {
|
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]
|
#[test]
|
||||||
fn test_should_execute_remote_unknown_hostname() {
|
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]
|
#[test]
|
||||||
fn test_should_not_execute_remote_same_hostname() {
|
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]
|
#[test]
|
||||||
fn test_should_not_execute_remote_same_hostname_with_user() {
|
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]
|
#[test]
|
||||||
fn test_should_execute_remote_matching_limit() {
|
fn test_should_execute_remote_matching_limit() {
|
||||||
let mut config = config();
|
let mut config = config();
|
||||||
config.opt = CommandLineArgs::parse_from(["topgrade", "--remote-host-limit", "remote_hostname"]);
|
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]
|
#[test]
|
||||||
fn test_should_not_execute_remote_not_matching_limit() {
|
fn test_should_not_execute_remote_not_matching_limit() {
|
||||||
let mut config = config();
|
let mut config = config();
|
||||||
config.opt = CommandLineArgs::parse_from(["topgrade", "--remote-host-limit", "other_hostname"]);
|
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
|
/// Clears the interrupted flag
|
||||||
pub fn unset_interrupted() {
|
pub fn unset_interrupted() {
|
||||||
debug_assert!(INTERRUPTED.load(Ordering::SeqCst));
|
debug_assert!(INTERRUPTED.load(Ordering::SeqCst));
|
||||||
INTERRUPTED.store(false, Ordering::SeqCst)
|
INTERRUPTED.store(false, Ordering::SeqCst);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn set_interrupted() {
|
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.
|
/// Handle SIGINT. Set the interruption flag.
|
||||||
extern "C" fn handle_sigint(_: i32) {
|
extern "C" fn handle_sigint(_: i32) {
|
||||||
set_interrupted()
|
set_interrupted();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Set the necessary signal handlers.
|
/// Set the necessary signal handlers.
|
||||||
|
|||||||
@@ -152,7 +152,10 @@ impl Executor {
|
|||||||
let result = match self {
|
let result = match self {
|
||||||
Executor::Wet(c) => {
|
Executor::Wet(c) => {
|
||||||
debug!("Running {:?}", 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) => {
|
Executor::Dry(c) => {
|
||||||
c.dry_run();
|
c.dry_run();
|
||||||
@@ -166,7 +169,12 @@ impl Executor {
|
|||||||
/// See `std::process::Command::output`
|
/// See `std::process::Command::output`
|
||||||
pub fn output(&mut self) -> Result<ExecutorOutput> {
|
pub fn output(&mut self) -> Result<ExecutorOutput> {
|
||||||
match self {
|
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) => {
|
Executor::Dry(c) => {
|
||||||
c.dry_run();
|
c.dry_run();
|
||||||
Ok(ExecutorOutput::Dry)
|
Ok(ExecutorOutput::Dry)
|
||||||
@@ -180,7 +188,7 @@ impl Executor {
|
|||||||
pub fn status_checked_with_codes(&mut self, codes: &[i32]) -> Result<()> {
|
pub fn status_checked_with_codes(&mut self, codes: &[i32]) -> Result<()> {
|
||||||
match self {
|
match self {
|
||||||
Executor::Wet(c) => c.status_checked_with(|status| {
|
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(())
|
Ok(())
|
||||||
} else {
|
} else {
|
||||||
Err(())
|
Err(())
|
||||||
|
|||||||
22
src/main.rs
22
src/main.rs
@@ -25,7 +25,9 @@ use self::config::{CommandLineArgs, Config, Step};
|
|||||||
use self::error::StepFailed;
|
use self::error::StepFailed;
|
||||||
#[cfg(all(windows, feature = "self-update"))]
|
#[cfg(all(windows, feature = "self-update"))]
|
||||||
use self::error::Upgraded;
|
use self::error::Upgraded;
|
||||||
|
#[allow(clippy::wildcard_imports)]
|
||||||
use self::steps::{remote::*, *};
|
use self::steps::{remote::*, *};
|
||||||
|
#[allow(clippy::wildcard_imports)]
|
||||||
use self::terminal::*;
|
use self::terminal::*;
|
||||||
|
|
||||||
use self::utils::{hostname, install_color_eyre, install_tracing, update_tracing};
|
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
|
// Init and load the i18n files
|
||||||
i18n!("locales", fallback = "en");
|
i18n!("locales", fallback = "en");
|
||||||
|
|
||||||
|
#[allow(clippy::too_many_lines)]
|
||||||
fn run() -> Result<()> {
|
fn run() -> Result<()> {
|
||||||
install_color_eyre()?;
|
install_color_eyre()?;
|
||||||
ctrlc::set_handler();
|
ctrlc::set_handler();
|
||||||
@@ -248,6 +251,9 @@ fn run() -> Result<()> {
|
|||||||
runner.execute(Step::Lure, "LURE", || linux::run_lure_update(&ctx))?;
|
runner.execute(Step::Lure, "LURE", || linux::run_lure_update(&ctx))?;
|
||||||
runner.execute(Step::Waydroid, "Waydroid", || linux::run_waydroid(&ctx))?;
|
runner.execute(Step::Waydroid, "Waydroid", || linux::run_waydroid(&ctx))?;
|
||||||
runner.execute(Step::AutoCpufreq, "auto-cpufreq", || linux::run_auto_cpufreq(&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")]
|
#[cfg(target_os = "macos")]
|
||||||
@@ -369,9 +375,13 @@ fn run() -> Result<()> {
|
|||||||
runner.execute(Step::Opam, "opam", || generic::run_opam_update(&ctx))?;
|
runner.execute(Step::Opam, "opam", || generic::run_opam_update(&ctx))?;
|
||||||
runner.execute(Step::Vcpkg, "vcpkg", || generic::run_vcpkg_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::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", || {
|
runner.execute(Step::Vscode, "Visual Studio Code extensions", || {
|
||||||
generic::run_vscode_extensions_update(&ctx)
|
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::Conda, "conda", || generic::run_conda_update(&ctx))?;
|
||||||
runner.execute(Step::Mamba, "mamba", || generic::run_mamba_update(&ctx))?;
|
runner.execute(Step::Mamba, "mamba", || generic::run_mamba_update(&ctx))?;
|
||||||
runner.execute(Step::Pixi, "pixi", || generic::run_pixi_update(&ctx))?;
|
runner.execute(Step::Pixi, "pixi", || generic::run_pixi_update(&ctx))?;
|
||||||
@@ -435,6 +445,10 @@ fn run() -> Result<()> {
|
|||||||
runner.execute(Step::Zvm, "ZVM", || generic::run_zvm(&ctx))?;
|
runner.execute(Step::Zvm, "ZVM", || generic::run_zvm(&ctx))?;
|
||||||
runner.execute(Step::Aqua, "aqua", || generic::run_aqua(&ctx))?;
|
runner.execute(Step::Aqua, "aqua", || generic::run_aqua(&ctx))?;
|
||||||
runner.execute(Step::Bun, "bun", || generic::run_bun(&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 {
|
if should_run_powershell {
|
||||||
runner.execute(Step::Powershell, "Powershell Modules Update", || {
|
runner.execute(Step::Powershell, "Powershell Modules Update", || {
|
||||||
@@ -491,13 +505,13 @@ fn run() -> Result<()> {
|
|||||||
print_info(t!("\n(R)eboot\n(S)hell\n(Q)uit"));
|
print_info(t!("\n(R)eboot\n(S)hell\n(Q)uit"));
|
||||||
loop {
|
loop {
|
||||||
match get_key() {
|
match get_key() {
|
||||||
Ok(Key::Char('s')) | Ok(Key::Char('S')) => {
|
Ok(Key::Char('s' | 'S')) => {
|
||||||
run_shell().context("Failed to execute shell")?;
|
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")?;
|
reboot().context("Failed to reboot")?;
|
||||||
}
|
}
|
||||||
Ok(Key::Char('q')) | Ok(Key::Char('Q')) => (),
|
Ok(Key::Char('q' | 'Q')) => (),
|
||||||
_ => {
|
_ => {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@@ -516,7 +530,7 @@ fn run() -> Result<()> {
|
|||||||
t!("Topgrade finished successfully")
|
t!("Topgrade finished successfully")
|
||||||
},
|
},
|
||||||
Some(Duration::from_secs(10)),
|
Some(Duration::from_secs(10)),
|
||||||
)
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
if failed {
|
if failed {
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ use rust_i18n::t;
|
|||||||
use self_update_crate::backends::github::Update;
|
use self_update_crate::backends::github::Update;
|
||||||
use self_update_crate::update::UpdateStatus;
|
use self_update_crate::update::UpdateStatus;
|
||||||
|
|
||||||
use super::terminal::*;
|
use super::terminal::{print_info, print_separator};
|
||||||
#[cfg(windows)]
|
#[cfg(windows)]
|
||||||
use crate::error::Upgraded;
|
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")?;
|
list_containers(&crt, ctx.config().containers_ignored_tags()).context("Failed to list Docker containers")?;
|
||||||
debug!("Containers to inspect: {:?}", containers);
|
debug!("Containers to inspect: {:?}", containers);
|
||||||
|
|
||||||
for container in containers.iter() {
|
for container in &containers {
|
||||||
debug!("Pulling container '{}'", container);
|
debug!("Pulling container '{}'", container);
|
||||||
let args = vec![
|
let args = vec![
|
||||||
"pull",
|
"pull",
|
||||||
|
|||||||
@@ -1,9 +1,4 @@
|
|||||||
(when (fboundp 'paradox-upgrade-packages)
|
(when (featurep 'package)
|
||||||
(progn
|
(if (fboundp 'package-upgrade-all)
|
||||||
(unless (boundp 'paradox-github-token)
|
(package-upgrade-all nil)
|
||||||
(setq paradox-github-token t))
|
(message "Your Emacs version doesn't support unattended packages upgrade")))
|
||||||
(paradox-upgrade-packages)
|
|
||||||
(princ
|
|
||||||
(if (get-buffer "*Paradox Report*")
|
|
||||||
(with-current-buffer "*Paradox Report*" (buffer-string))
|
|
||||||
"\nNothing to upgrade\n"))))
|
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
#![allow(unused_imports)]
|
#![allow(unused_imports)]
|
||||||
|
|
||||||
use std::ffi::OsStr;
|
use std::ffi::{OsStr, OsString};
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
use std::process::Command;
|
use std::process::Command;
|
||||||
use std::{env, path::Path};
|
use std::{env, path::Path};
|
||||||
@@ -9,6 +9,9 @@ use std::{fs, io::Write};
|
|||||||
use color_eyre::eyre::eyre;
|
use color_eyre::eyre::eyre;
|
||||||
use color_eyre::eyre::Context;
|
use color_eyre::eyre::Context;
|
||||||
use color_eyre::eyre::Result;
|
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 rust_i18n::t;
|
||||||
use semver::Version;
|
use semver::Version;
|
||||||
use tempfile::tempfile_in;
|
use tempfile::tempfile_in;
|
||||||
@@ -40,8 +43,7 @@ pub fn is_wsl() -> Result<bool> {
|
|||||||
|
|
||||||
pub fn run_cargo_update(ctx: &ExecutionContext) -> Result<()> {
|
pub fn run_cargo_update(ctx: &ExecutionContext) -> Result<()> {
|
||||||
let cargo_dir = env::var_os("CARGO_HOME")
|
let cargo_dir = env::var_os("CARGO_HOME")
|
||||||
.map(PathBuf::from)
|
.map_or_else(|| HOME_DIR.join(".cargo"), PathBuf::from)
|
||||||
.unwrap_or_else(|| HOME_DIR.join(".cargo"))
|
|
||||||
.require()?;
|
.require()?;
|
||||||
require("cargo").or_else(|_| {
|
require("cargo").or_else(|_| {
|
||||||
require_option(
|
require_option(
|
||||||
@@ -60,13 +62,11 @@ pub fn run_cargo_update(ctx: &ExecutionContext) -> Result<()> {
|
|||||||
let cargo_update = require("cargo-install-update")
|
let cargo_update = require("cargo-install-update")
|
||||||
.ok()
|
.ok()
|
||||||
.or_else(|| cargo_dir.join("bin/cargo-install-update").if_exists());
|
.or_else(|| cargo_dir.join("bin/cargo-install-update").if_exists());
|
||||||
let cargo_update = match cargo_update {
|
|
||||||
Some(e) => e,
|
let Some(cargo_update) = cargo_update else {
|
||||||
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`");
|
||||||
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);
|
||||||
print_warning(&message);
|
return Err(SkipStep(message).into());
|
||||||
return Err(SkipStep(message).into());
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
ctx.run_type()
|
ctx.run_type()
|
||||||
@@ -78,14 +78,11 @@ pub fn run_cargo_update(ctx: &ExecutionContext) -> Result<()> {
|
|||||||
let cargo_cache = require("cargo-cache")
|
let cargo_cache = require("cargo-cache")
|
||||||
.ok()
|
.ok()
|
||||||
.or_else(|| cargo_dir.join("bin/cargo-cache").if_exists());
|
.or_else(|| cargo_dir.join("bin/cargo-cache").if_exists());
|
||||||
match cargo_cache {
|
if let Some(e) = cargo_cache {
|
||||||
Some(e) => {
|
ctx.run_type().execute(e).args(["-a"]).status_checked()?;
|
||||||
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`");
|
||||||
None => {
|
print_warning(message);
|
||||||
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);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -229,6 +226,13 @@ pub fn run_apm(ctx: &ExecutionContext) -> Result<()> {
|
|||||||
pub fn run_aqua(ctx: &ExecutionContext) -> Result<()> {
|
pub fn run_aqua(ctx: &ExecutionContext) -> Result<()> {
|
||||||
let aqua = require("aqua")?;
|
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");
|
print_separator("Aqua");
|
||||||
if ctx.run_type().dry() {
|
if ctx.run_type().dry() {
|
||||||
println!("{}", t!("Updating aqua ..."));
|
println!("{}", t!("Updating aqua ..."));
|
||||||
@@ -258,10 +262,35 @@ pub fn run_elan(ctx: &ExecutionContext) -> Result<()> {
|
|||||||
let elan = require("elan")?;
|
let elan = require("elan")?;
|
||||||
|
|
||||||
print_separator("elan");
|
print_separator("elan");
|
||||||
ctx.run_type()
|
|
||||||
.execute(&elan)
|
let disabled_error_msg = "self-update is disabled";
|
||||||
.args(["self", "update"])
|
let executor_output = ctx.run_type().execute(&elan).args(["self", "update"]).output()?;
|
||||||
.status_checked()?;
|
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()
|
ctx.run_type().execute(&elan).arg("update").status_checked()
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -277,7 +306,13 @@ pub fn run_juliaup(ctx: &ExecutionContext) -> Result<()> {
|
|||||||
.status_checked()?;
|
.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<()> {
|
pub fn run_choosenim(ctx: &ExecutionContext) -> Result<()> {
|
||||||
@@ -375,6 +410,48 @@ pub fn run_vcpkg_update(ctx: &ExecutionContext) -> Result<()> {
|
|||||||
command.args(["upgrade", "--no-dry-run"]).status_checked()
|
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<()> {
|
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)
|
// 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()? {
|
if is_wsl()? {
|
||||||
@@ -392,7 +469,7 @@ pub fn run_vscode_extensions_update(ctx: &ExecutionContext) -> Result<()> {
|
|||||||
.lines()
|
.lines()
|
||||||
.next()
|
.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()),
|
_ => return Err(SkipStep(String::from("Cannot find vscode version")).into()),
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -402,10 +479,19 @@ pub fn run_vscode_extensions_update(ctx: &ExecutionContext) -> Result<()> {
|
|||||||
|
|
||||||
print_separator("Visual Studio Code extensions");
|
print_separator("Visual Studio Code extensions");
|
||||||
|
|
||||||
ctx.run_type()
|
if let Some(profile) = ctx.config().vscode_profile() {
|
||||||
.execute(vscode)
|
ctx.run_type()
|
||||||
.arg("--update-extensions")
|
.execute(vscode)
|
||||||
.status_checked()
|
.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<()> {
|
pub fn run_pipx_update(ctx: &ExecutionContext) -> Result<()> {
|
||||||
@@ -422,12 +508,22 @@ pub fn run_pipx_update(ctx: &ExecutionContext) -> Result<()> {
|
|||||||
.map(|s| s.stdout.trim().to_owned());
|
.map(|s| s.stdout.trim().to_owned());
|
||||||
let version = Version::parse(&version_str?);
|
let version = Version::parse(&version_str?);
|
||||||
if matches!(version, Ok(version) if version >= Version::new(1, 4, 0)) {
|
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()
|
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<()> {
|
pub fn run_conda_update(ctx: &ExecutionContext) -> Result<()> {
|
||||||
let conda = require("conda")?;
|
let conda = require("conda")?;
|
||||||
|
|
||||||
@@ -441,19 +537,45 @@ pub fn run_conda_update(ctx: &ExecutionContext) -> Result<()> {
|
|||||||
|
|
||||||
print_separator("Conda");
|
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"]);
|
command.args(["update", "--all", "-n", "base"]);
|
||||||
if ctx.config().yes(Step::Conda) {
|
if ctx.config().yes(Step::Conda) {
|
||||||
command.arg("--yes");
|
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<()> {
|
pub fn run_pixi_update(ctx: &ExecutionContext) -> Result<()> {
|
||||||
let pixi = require("pixi")?;
|
let pixi = require("pixi")?;
|
||||||
print_separator("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<()> {
|
pub fn run_mamba_update(ctx: &ExecutionContext) -> Result<()> {
|
||||||
@@ -461,12 +583,23 @@ pub fn run_mamba_update(ctx: &ExecutionContext) -> Result<()> {
|
|||||||
|
|
||||||
print_separator("Mamba");
|
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"]);
|
command.args(["update", "--all", "-n", "base"]);
|
||||||
if ctx.config().yes(Step::Mamba) {
|
if ctx.config().yes(Step::Mamba) {
|
||||||
command.arg("--yes");
|
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<()> {
|
pub fn run_miktex_packages_update(ctx: &ExecutionContext) -> Result<()> {
|
||||||
@@ -488,7 +621,7 @@ pub fn run_pip3_update(ctx: &ExecutionContext) -> Result<()> {
|
|||||||
(Ok(py), _) => py,
|
(Ok(py), _) => py,
|
||||||
(Err(_), Ok(py3)) => py3,
|
(Err(_), Ok(py3)) => py3,
|
||||||
(Err(py_err), Err(py3_err)) => {
|
(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());
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -837,7 +970,7 @@ pub fn run_dotnet_upgrade(ctx: &ExecutionContext) -> Result<()> {
|
|||||||
.execute(&dotnet)
|
.execute(&dotnet)
|
||||||
.args(["tool", "update", package_name, "--global"])
|
.args(["tool", "update", package_name, "--global"])
|
||||||
.status_checked()
|
.status_checked()
|
||||||
.with_context(|| format!("Failed to update .NET package {:?}", package_name))?;
|
.with_context(|| format!("Failed to update .NET package {package_name:?}"))?;
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
@@ -1032,24 +1165,39 @@ pub fn run_poetry(ctx: &ExecutionContext) -> Result<()> {
|
|||||||
let poetry = require("poetry")?;
|
let poetry = require("poetry")?;
|
||||||
|
|
||||||
#[cfg(unix)]
|
#[cfg(unix)]
|
||||||
fn get_interpreter(poetry: &PathBuf) -> Result<PathBuf> {
|
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;
|
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)?;
|
let script = fs::read(poetry)?;
|
||||||
if let Some(r) = script.iter().position(|&b| b == b'\n') {
|
if let Some(c) = SHEBANG_REGEX.captures(&script) {
|
||||||
let first_line = &script[..r];
|
let interpreter = OsStr::from_bytes(&c[1]).into();
|
||||||
if first_line.starts_with(b"#!") {
|
let args = c.get(2).map(|args| OsStr::from_bytes(args.as_bytes()).into());
|
||||||
return Ok(OsStr::from_bytes(&first_line[2..]).into());
|
return Ok((interpreter, args));
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Err(eyre!("Could not find shebang"))
|
Err(eyre!("Could not find shebang"))
|
||||||
}
|
}
|
||||||
#[cfg(windows)]
|
#[cfg(windows)]
|
||||||
fn get_interpreter(poetry: &PathBuf) -> Result<PathBuf> {
|
fn get_interpreter(poetry: &PathBuf) -> Result<(PathBuf, Option<OsString>)> {
|
||||||
let data = fs::read(poetry)?;
|
// 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.
|
||||||
|
|
||||||
// https://bitbucket.org/vinay.sajip/simple_launcher/src/master/compare_launchers.py
|
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") {
|
let pos = match data.windows(4).rposition(|b| b == b"PK\x05\x06") {
|
||||||
Some(i) => i,
|
Some(i) => i,
|
||||||
@@ -1068,29 +1216,40 @@ pub fn run_poetry(ctx: &ExecutionContext) -> Result<()> {
|
|||||||
return Err(eyre!("Invalid ZIP archive"));
|
return Err(eyre!("Invalid ZIP archive"));
|
||||||
}
|
}
|
||||||
let arc_pos = pos - cdr_size - cdr_offset;
|
let arc_pos = pos - cdr_size - cdr_offset;
|
||||||
let shebang = match data[..arc_pos].windows(2).rposition(|b| b == b"#!") {
|
match data[..arc_pos].windows(2).rposition(|b| b == b"#!") {
|
||||||
Some(l) => &data[l + 2..arc_pos - 1],
|
Some(l) => {
|
||||||
None => return Err(eyre!("Could not find shebang")),
|
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 is utf8
|
// shebang line should be valid utf8
|
||||||
Ok(std::str::from_utf8(shebang)?.into())
|
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() {
|
if ctx.config().poetry_force_self_update() {
|
||||||
debug!("forcing poetry self update");
|
debug!("forcing poetry self update");
|
||||||
} else {
|
} else {
|
||||||
let interpreter = match get_interpreter(&poetry) {
|
let (interp, interp_args) = get_interpreter(&poetry)
|
||||||
Ok(p) => p,
|
.map_err(|e| SkipStep(format!("Could not find interpreter for {}: {}", poetry.display(), e)))?;
|
||||||
Err(e) => {
|
debug!("poetry interpreter: {:?}, args: {:?}", interp, interp_args);
|
||||||
return Err(SkipStep(format!("Could not find interpreter for {}: {}", poetry.display(), e)).into())
|
|
||||||
}
|
|
||||||
};
|
|
||||||
debug!("poetry interpreter: {}", interpreter.display());
|
|
||||||
|
|
||||||
let check_official_install_script =
|
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')";
|
"import sys; from os import path; print('Y') if path.isfile(path.join(sys.prefix, 'poetry_env')) else print('N')";
|
||||||
let output = Command::new(&interpreter)
|
let mut command = Command::new(&interp);
|
||||||
|
if let Some(args) = interp_args {
|
||||||
|
command.arg(args);
|
||||||
|
}
|
||||||
|
let output = command
|
||||||
.args(["-c", check_official_install_script])
|
.args(["-c", check_official_install_script])
|
||||||
.output_checked_utf8()?;
|
.output_checked_utf8()?;
|
||||||
let stdout = output.stdout.trim();
|
let stdout = output.stdout.trim();
|
||||||
@@ -1129,8 +1288,7 @@ pub fn run_uv(ctx: &ExecutionContext) -> Result<()> {
|
|||||||
ctx.run_type()
|
ctx.run_type()
|
||||||
.execute(&uv_exec)
|
.execute(&uv_exec)
|
||||||
.args(["self", "update"])
|
.args(["self", "update"])
|
||||||
.status_checked()
|
.status_checked()?;
|
||||||
.ok();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ctx.run_type()
|
ctx.run_type()
|
||||||
@@ -1155,3 +1313,87 @@ pub fn run_bun(ctx: &ExecutionContext) -> Result<()> {
|
|||||||
|
|
||||||
ctx.run_type().execute(bun).arg("upgrade").status_checked()
|
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!(
|
print_warning(t!(
|
||||||
"Path {pattern} did not contain any git repositories",
|
"Path {pattern} did not contain any git repositories",
|
||||||
pattern = pattern
|
pattern = pattern
|
||||||
))
|
));
|
||||||
});
|
});
|
||||||
|
|
||||||
if repos.is_repos_empty() {
|
if repos.is_repos_empty() {
|
||||||
@@ -207,10 +207,13 @@ impl RepoStep {
|
|||||||
|
|
||||||
return output;
|
return output;
|
||||||
}
|
}
|
||||||
Err(e) => match e.kind() {
|
Err(e) => {
|
||||||
io::ErrorKind::NotFound => debug!("{} does not exist", path.as_ref().display()),
|
if e.kind() == io::ErrorKind::NotFound {
|
||||||
_ => error!("Error looking for {}: {e}", path.as_ref().display(),),
|
debug!("{} does not exist", path.as_ref().display());
|
||||||
},
|
} else {
|
||||||
|
error!("Error looking for {}: {e}", path.as_ref().display());
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
None
|
None
|
||||||
@@ -321,7 +324,7 @@ impl RepoStep {
|
|||||||
.output()
|
.output()
|
||||||
.await?;
|
.await?;
|
||||||
let result = output_checked_utf8(pull_output)
|
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()));
|
.wrap_err_with(|| format!("Failed to pull {}", repo.as_ref().display()));
|
||||||
|
|
||||||
if result.is_err() {
|
if result.is_err() {
|
||||||
@@ -359,7 +362,7 @@ impl RepoStep {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
result.map(|_| ())
|
result
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Pull the repositories specified in `self.repos`.
|
/// Pull the repositories specified in `self.repos`.
|
||||||
@@ -410,7 +413,7 @@ impl RepoStep {
|
|||||||
let basic_rt = runtime::Runtime::new()?;
|
let basic_rt = runtime::Runtime::new()?;
|
||||||
let results = basic_rt.block_on(async { stream_of_futures.collect::<Vec<Result<()>>>().await });
|
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(()))
|
error.unwrap_or(Ok(()))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -87,7 +87,7 @@ impl NPM {
|
|||||||
.args(["--version"])
|
.args(["--version"])
|
||||||
.output_checked_utf8()
|
.output_checked_utf8()
|
||||||
.map(|s| s.stdout.trim().to_owned());
|
.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<()> {
|
fn upgrade(&self, ctx: &ExecutionContext, use_sudo: bool) -> Result<()> {
|
||||||
@@ -266,7 +266,7 @@ impl Deno {
|
|||||||
.args(["-V"])
|
.args(["-V"])
|
||||||
.output_checked_utf8()
|
.output_checked_utf8()
|
||||||
.map(|s| s.stdout.trim().to_owned().split_off(5)); // remove "deno " prefix
|
.map(|s| s.stdout.trim().to_owned().split_off(5)); // remove "deno " prefix
|
||||||
Version::parse(&version_str?).map_err(|err| err.into())
|
Version::parse(&version_str?).map_err(std::convert::Into::into)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -399,7 +399,7 @@ pub fn run_volta_packages_upgrade(ctx: &ExecutionContext) -> Result<()> {
|
|||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
|
|
||||||
for package in installed_packages.iter() {
|
for package in &installed_packages {
|
||||||
ctx.run_type()
|
ctx.run_type()
|
||||||
.execute(&volta)
|
.execute(&volta)
|
||||||
.args(["install", package])
|
.args(["install", package])
|
||||||
|
|||||||
@@ -60,19 +60,7 @@ impl Distribution {
|
|||||||
Some("wolfi") => Distribution::Wolfi,
|
Some("wolfi") => Distribution::Wolfi,
|
||||||
Some("centos") | Some("rhel") | Some("ol") => Distribution::CentOS,
|
Some("centos") | Some("rhel") | Some("ol") => Distribution::CentOS,
|
||||||
Some("clear-linux-os") => Distribution::ClearLinux,
|
Some("clear-linux-os") => Distribution::ClearLinux,
|
||||||
Some("fedora") => {
|
Some("fedora") => Distribution::match_fedora_variant(&variant),
|
||||||
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("nilrt") => Distribution::NILRT,
|
Some("nilrt") => Distribution::NILRT,
|
||||||
Some("nobara") => Distribution::Nobara,
|
Some("nobara") => Distribution::Nobara,
|
||||||
Some("void") => Distribution::Void,
|
Some("void") => Distribution::Void,
|
||||||
@@ -109,7 +97,7 @@ impl Distribution {
|
|||||||
} else if id_like.contains(&"alpine") {
|
} else if id_like.contains(&"alpine") {
|
||||||
return Ok(Distribution::Alpine);
|
return Ok(Distribution::Alpine);
|
||||||
} else if id_like.contains(&"fedora") {
|
} else if id_like.contains(&"fedora") {
|
||||||
return Ok(Distribution::Fedora);
|
return Ok(Distribution::match_fedora_variant(&variant));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return Err(TopgradeError::UnknownLinuxDistribution.into());
|
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> {
|
pub fn detect() -> Result<Self> {
|
||||||
if PathBuf::from("/bedrock").exists() {
|
if PathBuf::from("/bedrock").exists() {
|
||||||
return Ok(Distribution::Bedrock);
|
return Ok(Distribution::Bedrock);
|
||||||
@@ -230,7 +227,9 @@ fn upgrade_redhat(ctx: &ExecutionContext) -> Result<()> {
|
|||||||
let sudo = require_option(ctx.sudo().as_ref(), get_require_sudo_string())?;
|
let sudo = require_option(ctx.sudo().as_ref(), get_require_sudo_string())?;
|
||||||
return ctx.run_type().execute(sudo).arg(&bootc).arg("upgrade").status_checked();
|
return ctx.run_type().execute(sudo).arg(&bootc).arg("upgrade").status_checked();
|
||||||
}
|
}
|
||||||
} else if let Some(ostree) = which("rpm-ostree") {
|
}
|
||||||
|
|
||||||
|
if let Some(ostree) = which("rpm-ostree") {
|
||||||
if ctx.config().rpm_ostree() {
|
if ctx.config().rpm_ostree() {
|
||||||
let mut command = ctx.run_type().execute(ostree);
|
let mut command = ctx.run_type().execute(ostree);
|
||||||
command.arg("upgrade");
|
command.arg("upgrade");
|
||||||
@@ -1118,6 +1117,17 @@ pub fn run_auto_cpufreq(ctx: &ExecutionContext) -> Result<()> {
|
|||||||
.status_checked()
|
.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)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
@@ -1286,4 +1296,24 @@ mod tests {
|
|||||||
fn test_nilrt() {
|
fn test_nilrt() {
|
||||||
test_template(include_str!("os_release/nilrt"), Distribution::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)
|
.execute(&xcodes)
|
||||||
.args([
|
.args([
|
||||||
"uninstall",
|
"uninstall",
|
||||||
releases_new_installed.iter().next().cloned().unwrap_or_default(),
|
releases_new_installed.iter().next().copied().unwrap_or_default(),
|
||||||
])
|
])
|
||||||
.status_checked();
|
.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<()> {
|
pub fn process_xcodes_releases(releases_filtered: Vec<String>, should_ask: bool, ctx: &ExecutionContext) -> Result<()> {
|
||||||
let xcodes = require("xcodes")?;
|
let xcodes = require("xcodes")?;
|
||||||
|
|
||||||
if releases_filtered
|
if releases_filtered.last().map_or(true, |s| !s.contains("(Installed)")) && !releases_filtered.is_empty() {
|
||||||
.last()
|
|
||||||
.map(|s| !s.contains("(Installed)"))
|
|
||||||
.unwrap_or(true)
|
|
||||||
&& !releases_filtered.is_empty()
|
|
||||||
{
|
|
||||||
println!(
|
println!(
|
||||||
"{} {}",
|
"{} {}",
|
||||||
t!("New Xcode release detected:"),
|
t!("New Xcode release detected:"),
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ use std::fs;
|
|||||||
|
|
||||||
fn is_openbsd_current(ctx: &ExecutionContext) -> Result<bool> {
|
fn is_openbsd_current(ctx: &ExecutionContext) -> Result<bool> {
|
||||||
let motd_content = fs::read_to_string("/etc/motd")?;
|
let motd_content = fs::read_to_string("/etc/motd")?;
|
||||||
let is_current = motd_content.contains("-current");
|
let is_current = ["-current", "-beta"].iter().any(|&s| motd_content.contains(s));
|
||||||
if ctx.config().dry_run() {
|
if ctx.config().dry_run() {
|
||||||
println!("{}", t!("Would check if OpenBSD is -current"));
|
println!("{}", t!("Would check if OpenBSD is -current"));
|
||||||
Ok(is_current)
|
Ok(is_current)
|
||||||
@@ -28,10 +28,11 @@ pub fn upgrade_openbsd(ctx: &ExecutionContext) -> Result<()> {
|
|||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut args = vec!["/usr/sbin/sysupgrade", "-n"];
|
let args = if is_current {
|
||||||
if is_current {
|
vec!["/usr/sbin/sysupgrade", "-sn"]
|
||||||
args.push("-s");
|
} else {
|
||||||
}
|
vec!["/usr/sbin/syspatch"]
|
||||||
|
};
|
||||||
|
|
||||||
ctx.run_type().execute(sudo).args(&args).status_checked()
|
ctx.run_type().execute(sudo).args(&args).status_checked()
|
||||||
}
|
}
|
||||||
|
|||||||
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'
|
||||||
@@ -463,7 +463,7 @@ pub fn run_nix(ctx: &ExecutionContext) -> Result<()> {
|
|||||||
|
|
||||||
lazy_static! {
|
lazy_static! {
|
||||||
static ref NIX_VERSION_REGEX: Regex =
|
static ref NIX_VERSION_REGEX: Regex =
|
||||||
Regex::new(r#"^nix \([^)]*\) ([0-9.]+)"#).expect("Nix version regex always compiles");
|
Regex::new(r"^nix \([^)]*\) ([0-9.]+)").expect("Nix version regex always compiles");
|
||||||
}
|
}
|
||||||
|
|
||||||
if get_version_cmd_first_line_stdout.is_empty() {
|
if get_version_cmd_first_line_stdout.is_empty() {
|
||||||
@@ -611,8 +611,7 @@ fn nix_profile_dir(nix: &Path) -> Result<Option<PathBuf>> {
|
|||||||
if user_env
|
if user_env
|
||||||
.file_name()
|
.file_name()
|
||||||
.and_then(|name| name.to_str())
|
.and_then(|name| name.to_str())
|
||||||
.map(|name| name.ends_with("user-environment"))
|
.is_some_and(|name| name.ends_with("user-environment"))
|
||||||
.unwrap_or(false)
|
|
||||||
{
|
{
|
||||||
Some(profile_dir)
|
Some(profile_dir)
|
||||||
} else {
|
} else {
|
||||||
@@ -637,10 +636,33 @@ pub fn run_asdf(ctx: &ExecutionContext) -> Result<()> {
|
|||||||
let asdf = require("asdf")?;
|
let asdf = require("asdf")?;
|
||||||
|
|
||||||
print_separator("asdf");
|
print_separator("asdf");
|
||||||
ctx.run_type()
|
|
||||||
.execute(&asdf)
|
// asdf (>= 0.15.0) won't support the self-update command
|
||||||
.arg("update")
|
//
|
||||||
.status_checked_with_codes(&[42])?;
|
// 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()
|
ctx.run_type()
|
||||||
.execute(&asdf)
|
.execute(&asdf)
|
||||||
@@ -694,9 +716,7 @@ pub fn run_pyenv(ctx: &ExecutionContext) -> Result<()> {
|
|||||||
let pyenv = require("pyenv")?;
|
let pyenv = require("pyenv")?;
|
||||||
print_separator("pyenv");
|
print_separator("pyenv");
|
||||||
|
|
||||||
let pyenv_dir = var("PYENV_ROOT")
|
let pyenv_dir = var("PYENV_ROOT").map_or_else(|_| HOME_DIR.join(".pyenv"), PathBuf::from);
|
||||||
.map(PathBuf::from)
|
|
||||||
.unwrap_or_else(|_| HOME_DIR.join(".pyenv"));
|
|
||||||
|
|
||||||
if !pyenv_dir.exists() {
|
if !pyenv_dir.exists() {
|
||||||
return Err(SkipStep(t!("Pyenv is installed, but $PYENV_ROOT is not set correctly").to_string()).into());
|
return Err(SkipStep(t!("Pyenv is installed, but $PYENV_ROOT is not set correctly").to_string()).into());
|
||||||
@@ -717,8 +737,7 @@ pub fn run_sdkman(ctx: &ExecutionContext) -> Result<()> {
|
|||||||
let bash = require("bash")?;
|
let bash = require("bash")?;
|
||||||
|
|
||||||
let sdkman_init_path = var("SDKMAN_DIR")
|
let sdkman_init_path = var("SDKMAN_DIR")
|
||||||
.map(PathBuf::from)
|
.map_or_else(|_| HOME_DIR.join(".sdkman"), PathBuf::from)
|
||||||
.unwrap_or_else(|_| HOME_DIR.join(".sdkman"))
|
|
||||||
.join("bin")
|
.join("bin")
|
||||||
.join("sdkman-init.sh")
|
.join("sdkman-init.sh")
|
||||||
.require()
|
.require()
|
||||||
@@ -727,8 +746,7 @@ pub fn run_sdkman(ctx: &ExecutionContext) -> Result<()> {
|
|||||||
print_separator("SDKMAN!");
|
print_separator("SDKMAN!");
|
||||||
|
|
||||||
let sdkman_config_path = var("SDKMAN_DIR")
|
let sdkman_config_path = var("SDKMAN_DIR")
|
||||||
.map(PathBuf::from)
|
.map_or_else(|_| HOME_DIR.join(".sdkman"), PathBuf::from)
|
||||||
.unwrap_or_else(|_| HOME_DIR.join(".sdkman"))
|
|
||||||
.join("etc")
|
.join("etc")
|
||||||
.join("config")
|
.join("config")
|
||||||
.require()?;
|
.require()?;
|
||||||
@@ -781,9 +799,7 @@ pub fn run_bun_packages(ctx: &ExecutionContext) -> Result<()> {
|
|||||||
|
|
||||||
print_separator(t!("Bun Packages"));
|
print_separator(t!("Bun Packages"));
|
||||||
|
|
||||||
let mut package_json: PathBuf = var("BUN_INSTALL")
|
let mut package_json: PathBuf = var("BUN_INSTALL").map_or_else(|_| HOME_DIR.join(".bun"), PathBuf::from);
|
||||||
.map(PathBuf::from)
|
|
||||||
.unwrap_or_else(|_| HOME_DIR.join(".bun"));
|
|
||||||
package_json.push("install/global/package.json");
|
package_json.push("install/global/package.json");
|
||||||
|
|
||||||
if !package_json.exists() {
|
if !package_json.exists() {
|
||||||
|
|||||||
@@ -42,10 +42,12 @@ pub fn run_winget(ctx: &ExecutionContext) -> Result<()> {
|
|||||||
|
|
||||||
print_separator("winget");
|
print_separator("winget");
|
||||||
|
|
||||||
ctx.run_type()
|
let mut args = vec!["upgrade", "--all"];
|
||||||
.execute(winget)
|
if ctx.config().winget_silent_install() {
|
||||||
.args(["upgrade", "--all"])
|
args.push("--silent");
|
||||||
.status_checked()
|
}
|
||||||
|
|
||||||
|
ctx.run_type().execute(winget).args(args).status_checked()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn run_scoop(ctx: &ExecutionContext) -> Result<()> {
|
pub fn run_scoop(ctx: &ExecutionContext) -> Result<()> {
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ use rust_i18n::t;
|
|||||||
use crate::command::CommandExt;
|
use crate::command::CommandExt;
|
||||||
use crate::execution_context::ExecutionContext;
|
use crate::execution_context::ExecutionContext;
|
||||||
use crate::terminal::{is_dumb, print_separator};
|
use crate::terminal::{is_dumb, print_separator};
|
||||||
use crate::utils::{require_option, which, PathExt};
|
use crate::utils::{require_option, which};
|
||||||
use crate::Step;
|
use crate::Step;
|
||||||
|
|
||||||
pub struct Powershell {
|
pub struct Powershell {
|
||||||
@@ -30,7 +30,7 @@ impl Powershell {
|
|||||||
.args(["-NoProfile", "-Command", "Split-Path $profile"])
|
.args(["-NoProfile", "-Command", "Split-Path $profile"])
|
||||||
.output_checked_utf8()
|
.output_checked_utf8()
|
||||||
.map(|output| PathBuf::from(output.stdout.trim()))
|
.map(|output| PathBuf::from(output.stdout.trim()))
|
||||||
.and_then(|p| p.require())
|
.and_then(super::super::utils::PathExt::require)
|
||||||
.ok()
|
.ok()
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -70,11 +70,11 @@ impl Powershell {
|
|||||||
let mut cmd = vec!["Update-Module"];
|
let mut cmd = vec!["Update-Module"];
|
||||||
|
|
||||||
if ctx.config().verbose() {
|
if ctx.config().verbose() {
|
||||||
cmd.push("-Verbose")
|
cmd.push("-Verbose");
|
||||||
}
|
}
|
||||||
|
|
||||||
if ctx.config().yes(Step::Powershell) {
|
if ctx.config().yes(Step::Powershell) {
|
||||||
cmd.push("-Force")
|
cmd.push("-Force");
|
||||||
}
|
}
|
||||||
|
|
||||||
println!("{}", t!("Updating modules..."));
|
println!("{}", t!("Updating modules..."));
|
||||||
|
|||||||
@@ -232,7 +232,7 @@ pub fn upgrade_vagrant_boxes(ctx: &ExecutionContext) -> Result<()> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if !found {
|
if !found {
|
||||||
println!("{}", t!("No outdated boxes"))
|
println!("{}", t!("No outdated boxes"));
|
||||||
} else {
|
} else {
|
||||||
ctx.run_type()
|
ctx.run_type()
|
||||||
.execute(&vagrant)
|
.execute(&vagrant)
|
||||||
|
|||||||
@@ -128,7 +128,7 @@ impl Tmux {
|
|||||||
.output_checked_utf8()?
|
.output_checked_utf8()?
|
||||||
.stdout
|
.stdout
|
||||||
.lines()
|
.lines()
|
||||||
.map(|l| l.parse())
|
.map(str::parse)
|
||||||
.collect::<Result<Vec<usize>, _>>()
|
.collect::<Result<Vec<usize>, _>>()
|
||||||
.context("Failed to compute tmux windows")
|
.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<()> {
|
pub fn run_command(ctx: &ExecutionContext, window_name: &str, command: &str) -> Result<()> {
|
||||||
let tmux = Tmux::new(ctx.config().tmux_config()?.args);
|
let tmux = Tmux::new(ctx.config().tmux_config()?.args);
|
||||||
|
|
||||||
match ctx.get_tmux_session() {
|
if let Some(session_name) = ctx.get_tmux_session() {
|
||||||
Some(session_name) => {
|
let indices = tmux.window_indices(&session_name)?;
|
||||||
let indices = tmux.window_indices(&session_name)?;
|
let last_window = indices
|
||||||
let last_window = indices
|
.iter()
|
||||||
.iter()
|
.last()
|
||||||
.last()
|
.ok_or_else(|| eyre!("tmux session {session_name} has no windows"))?;
|
||||||
.ok_or_else(|| eyre!("tmux session {session_name} has no windows"))?;
|
tmux.new_window(&session_name, &format!("{last_window}"), command)?;
|
||||||
tmux.new_window(&session_name, &format!("{last_window}"), command)?;
|
} else {
|
||||||
}
|
let name = tmux.new_unique_session("topgrade", window_name, command)?;
|
||||||
None => {
|
ctx.set_tmux_session(name);
|
||||||
let name = tmux.new_unique_session("topgrade", window_name, command)?;
|
|
||||||
ctx.set_tmux_session(name);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -65,7 +65,7 @@ fn upgrade(command: &mut Executor, ctx: &ExecutionContext) -> Result<()> {
|
|||||||
if !status.success() {
|
if !status.success() {
|
||||||
return Err(TopgradeError::ProcessFailed(command.get_program(), status).into());
|
return Err(TopgradeError::ProcessFailed(command.get_program(), status).into());
|
||||||
} else {
|
} else {
|
||||||
println!("{}", t!("Plugins upgraded"))
|
println!("{}", t!("Plugins upgraded"));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -30,9 +30,7 @@ pub fn run_zr(ctx: &ExecutionContext) -> Result<()> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn zdotdir() -> PathBuf {
|
fn zdotdir() -> PathBuf {
|
||||||
env::var("ZDOTDIR")
|
env::var("ZDOTDIR").map_or_else(|_| HOME_DIR.clone(), PathBuf::from)
|
||||||
.map(PathBuf::from)
|
|
||||||
.unwrap_or_else(|_| HOME_DIR.clone())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn zshrc() -> PathBuf {
|
pub fn zshrc() -> PathBuf {
|
||||||
@@ -66,8 +64,7 @@ pub fn run_antigen(ctx: &ExecutionContext) -> Result<()> {
|
|||||||
let zsh = require("zsh")?;
|
let zsh = require("zsh")?;
|
||||||
let zshrc = zshrc().require()?;
|
let zshrc = zshrc().require()?;
|
||||||
env::var("ADOTDIR")
|
env::var("ADOTDIR")
|
||||||
.map(PathBuf::from)
|
.map_or_else(|_| HOME_DIR.join("antigen.zsh"), PathBuf::from)
|
||||||
.unwrap_or_else(|_| HOME_DIR.join("antigen.zsh"))
|
|
||||||
.require()?;
|
.require()?;
|
||||||
|
|
||||||
print_separator("antigen");
|
print_separator("antigen");
|
||||||
@@ -83,8 +80,7 @@ pub fn run_zgenom(ctx: &ExecutionContext) -> Result<()> {
|
|||||||
let zsh = require("zsh")?;
|
let zsh = require("zsh")?;
|
||||||
let zshrc = zshrc().require()?;
|
let zshrc = zshrc().require()?;
|
||||||
env::var("ZGEN_SOURCE")
|
env::var("ZGEN_SOURCE")
|
||||||
.map(PathBuf::from)
|
.map_or_else(|_| HOME_DIR.join(".zgenom"), PathBuf::from)
|
||||||
.unwrap_or_else(|_| HOME_DIR.join(".zgenom"))
|
|
||||||
.require()?;
|
.require()?;
|
||||||
|
|
||||||
print_separator("zgenom");
|
print_separator("zgenom");
|
||||||
@@ -101,8 +97,7 @@ pub fn run_zplug(ctx: &ExecutionContext) -> Result<()> {
|
|||||||
zshrc().require()?;
|
zshrc().require()?;
|
||||||
|
|
||||||
env::var("ZPLUG_HOME")
|
env::var("ZPLUG_HOME")
|
||||||
.map(PathBuf::from)
|
.map_or_else(|_| HOME_DIR.join(".zplug"), PathBuf::from)
|
||||||
.unwrap_or_else(|_| HOME_DIR.join(".zplug"))
|
|
||||||
.require()?;
|
.require()?;
|
||||||
|
|
||||||
print_separator("zplug");
|
print_separator("zplug");
|
||||||
@@ -118,8 +113,7 @@ pub fn run_zinit(ctx: &ExecutionContext) -> Result<()> {
|
|||||||
let zshrc = zshrc().require()?;
|
let zshrc = zshrc().require()?;
|
||||||
|
|
||||||
env::var("ZINIT_HOME")
|
env::var("ZINIT_HOME")
|
||||||
.map(PathBuf::from)
|
.map_or_else(|_| XDG_DIRS.data_dir().join("zinit"), PathBuf::from)
|
||||||
.unwrap_or_else(|_| XDG_DIRS.data_dir().join("zinit"))
|
|
||||||
.require()?;
|
.require()?;
|
||||||
|
|
||||||
print_separator("zinit");
|
print_separator("zinit");
|
||||||
@@ -153,8 +147,7 @@ pub fn run_zim(ctx: &ExecutionContext) -> Result<()> {
|
|||||||
.output_checked_utf8()
|
.output_checked_utf8()
|
||||||
.map(|o| o.stdout)
|
.map(|o| o.stdout)
|
||||||
})
|
})
|
||||||
.map(PathBuf::from)
|
.map_or_else(|_| HOME_DIR.join(".zim"), PathBuf::from)
|
||||||
.unwrap_or_else(|_| HOME_DIR.join(".zim"))
|
|
||||||
.require()?;
|
.require()?;
|
||||||
|
|
||||||
print_separator("zim");
|
print_separator("zim");
|
||||||
|
|||||||
31
src/sudo.rs
31
src/sudo.rs
@@ -22,13 +22,28 @@ pub struct Sudo {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl 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.
|
/// Get the `sudo` binary for this platform.
|
||||||
pub fn detect() -> Option<Self> {
|
pub fn detect() -> Option<Self> {
|
||||||
which("doas")
|
which("doas")
|
||||||
.map(|p| (p, SudoKind::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("gsudo").map(|p| (p, SudoKind::Gsudo)))
|
||||||
.or_else(|| which("pkexec").map(|p| (p, SudoKind::Pkexec)))
|
.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)))
|
.or_else(|| which("please").map(|p| (p, SudoKind::Please)))
|
||||||
.map(|(path, kind)| Self { path, kind })
|
.map(|(path, kind)| Self { path, kind })
|
||||||
}
|
}
|
||||||
@@ -65,9 +80,11 @@ impl Sudo {
|
|||||||
cmd.arg("-v");
|
cmd.arg("-v");
|
||||||
}
|
}
|
||||||
SudoKind::Gsudo => {
|
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
|
// See: https://gerardog.github.io/gsudo/docs/usage
|
||||||
cmd.arg("status");
|
cmd.arg("echo");
|
||||||
}
|
}
|
||||||
SudoKind::Pkexec => {
|
SudoKind::Pkexec => {
|
||||||
// I don't think this does anything; `pkexec` usually asks for
|
// 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
|
// See: https://linux.die.net/man/1/pkexec
|
||||||
cmd.arg("echo");
|
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 => {
|
SudoKind::Please => {
|
||||||
// From `man please`
|
// From `man please`
|
||||||
// -w, --warm
|
// -w, --warm
|
||||||
@@ -115,6 +139,7 @@ pub enum SudoKind {
|
|||||||
Sudo,
|
Sudo,
|
||||||
Gsudo,
|
Gsudo,
|
||||||
Pkexec,
|
Pkexec,
|
||||||
|
Run0,
|
||||||
Please,
|
Please,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -52,9 +52,7 @@ impl Terminal {
|
|||||||
Self {
|
Self {
|
||||||
width: term.size_checked().map(|(_, w)| w),
|
width: term.size_checked().map(|(_, w)| w),
|
||||||
term,
|
term,
|
||||||
prefix: env::var("TOPGRADE_PREFIX")
|
prefix: env::var("TOPGRADE_PREFIX").map_or_else(|_| String::new(), |prefix| format!("({prefix}) ")),
|
||||||
.map(|prefix| format!("({prefix}) "))
|
|
||||||
.unwrap_or_else(|_| String::new()),
|
|
||||||
set_title: true,
|
set_title: true,
|
||||||
display_time: true,
|
display_time: true,
|
||||||
desktop_notification: false,
|
desktop_notification: false,
|
||||||
@@ -62,15 +60,15 @@ impl Terminal {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn set_desktop_notifications(&mut self, desktop_notifications: bool) {
|
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) {
|
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) {
|
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>) {
|
fn notify_desktop<P: AsRef<str>>(&self, message: P, timeout: Option<Duration>) {
|
||||||
@@ -223,8 +221,8 @@ impl Terminal {
|
|||||||
|
|
||||||
let answer = loop {
|
let answer = loop {
|
||||||
match self.term.read_key() {
|
match self.term.read_key() {
|
||||||
Ok(Key::Char('y')) | Ok(Key::Char('Y')) => break Ok(true),
|
Ok(Key::Char('y' | 'Y')) => break Ok(true),
|
||||||
Ok(Key::Char('s')) | Ok(Key::Char('S')) => {
|
Ok(Key::Char('s' | 'S')) => {
|
||||||
println!(
|
println!(
|
||||||
"\n\n{}\n",
|
"\n\n{}\n",
|
||||||
t!("Dropping you to shell. Fix what you need and then exit the shell.")
|
t!("Dropping you to shell. Fix what you need and then exit the shell.")
|
||||||
@@ -235,12 +233,12 @@ impl Terminal {
|
|||||||
break Ok(true);
|
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) => {
|
Err(e) => {
|
||||||
error!("Error reading from terminal: {}", e);
|
error!("Error reading from terminal: {}", e);
|
||||||
break Ok(false);
|
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")
|
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) {
|
pub fn print_separator<P: AsRef<str>>(message: P) {
|
||||||
TERMINAL.lock().unwrap().print_separator(message)
|
TERMINAL.lock().unwrap().print_separator(message);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
pub fn print_error<P: AsRef<str>, Q: AsRef<str>>(key: Q, message: P) {
|
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)]
|
#[allow(dead_code)]
|
||||||
pub fn print_warning<P: AsRef<str>>(message: P) {
|
pub fn print_warning<P: AsRef<str>>(message: P) {
|
||||||
TERMINAL.lock().unwrap().print_warning(message)
|
TERMINAL.lock().unwrap().print_warning(message);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
pub fn print_info<P: AsRef<str>>(message: P) {
|
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) {
|
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.
|
/// 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>) {
|
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) {
|
pub fn display_time(display_time: bool) {
|
||||||
|
|||||||
@@ -86,7 +86,7 @@ pub fn editor() -> Vec<String> {
|
|||||||
env::var("EDITOR")
|
env::var("EDITOR")
|
||||||
.unwrap_or_else(|_| String::from(if cfg!(windows) { "notepad" } else { "vi" }))
|
.unwrap_or_else(|_| String::from(if cfg!(windows) { "notepad" } else { "vi" }))
|
||||||
.split_whitespace()
|
.split_whitespace()
|
||||||
.map(|s| s.to_owned())
|
.map(std::borrow::ToOwned::to_owned)
|
||||||
.collect()
|
.collect()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user