Compare commits

...

18 Commits
v16.4.2 ... v17

Author SHA1 Message Date
GideonBear
5bd5f10f0c chore(deps): update clap-cargo to v0.18.x 2025-11-23 13:33:53 +01:00
GideonBear
bfaca61deb chore(deps): update base64ct, globset, ignore 2025-11-23 13:26:47 +01:00
GideonBear
b00c4c1503 chore: upgrade to edition 2024
Co-authored-by: Ehren Bendler <a5ehren@gmail.com>
2025-11-23 13:26:47 +01:00
GideonBear
54a722be21 chore(deb): update copyright
Co-authored-by: Ehren Bendler <a5ehren@gmail.com>
2025-11-23 13:26:47 +01:00
GideonBear
bf4555ed29 chore(deps): unpin toml
Co-authored-by: Ehren Bendler <a5ehren@gmail.com>
2025-11-23 13:26:47 +01:00
GideonBear
46eb74109e style: apply new clippy fixes 2025-11-23 13:26:47 +01:00
GideonBear
0bde798b4a chore(deps): bump etcetera to 0.11.0 2025-11-23 13:26:47 +01:00
GideonBear
ebb4448950 chore(deps): remove temporary transitive dependency pins 2025-11-23 13:26:46 +01:00
GideonBear
b2b51bc8d2 refactor: replace home dependency with std::env::home_dir 2025-11-23 13:26:06 +01:00
GideonBear
8840a273b4 chore!: bump MSRV to 1.87.0 2025-11-23 13:26:06 +01:00
Filip Czaplicki
50e55dea77 feat: add colors to --help/-h (#1553) 2025-11-23 13:15:50 +01:00
Rubin Bhandari
f7c9e42066 feat(mise): add support for parallel job configuration in mise (#1548)
Co-authored-by: Gideon <87426140+GideonBear@users.noreply.github.com>
2025-11-21 09:08:40 +01:00
Daniil Kulchenko
ef3ee7bea7 feat(brew): add Homebrew cask support for Linux (#1539) 2025-11-20 20:10:47 +01:00
renovate[bot]
8eb300c4fb chore(deps): update rust crate indexmap to v2.12.1 (#1550)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-11-20 19:33:19 +01:00
renovate[bot]
b7b99a725c chore(deps): update actions/checkout action to v6 (#1551)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-11-20 19:31:17 +01:00
Gideon
df090a89c4 docs: Add metadata to Python package for PyPI (#1549) 2025-11-20 19:25:56 +01:00
LILAY
856fa0ed5b docs(installation): update copr repo info in readme (#1545) 2025-11-20 17:28:39 +01:00
Rubin Bhandari
9bb5a680ac feat(mise): add mise configuration options for bump and interactive modes (#1546) 2025-11-20 17:28:13 +01:00
42 changed files with 242 additions and 145 deletions

View File

@@ -15,7 +15,7 @@ jobs:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- uses: actions/checkout@93cb6efe18208431cddfb8368fd83d5badbf9bfd # v5.0.1 - uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v6.0.0
with: with:
persist-credentials: false persist-credentials: false

View File

@@ -14,7 +14,7 @@ jobs:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- name: Checkout code - name: Checkout code
uses: actions/checkout@93cb6efe18208431cddfb8368fd83d5badbf9bfd # v5.0.1 uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v6.0.0
with: with:
persist-credentials: false persist-credentials: false

View File

@@ -24,7 +24,7 @@ jobs:
security-events: write security-events: write
steps: steps:
- name: Checkout code - name: Checkout code
uses: actions/checkout@93cb6efe18208431cddfb8368fd83d5badbf9bfd # v5.0.1 uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v6.0.0
with: with:
persist-credentials: false persist-credentials: false

View File

@@ -23,7 +23,7 @@ jobs:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- name: Checkout code - name: Checkout code
uses: actions/checkout@93cb6efe18208431cddfb8368fd83d5badbf9bfd # v5.0.1 uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v6.0.0
with: with:
persist-credentials: false persist-credentials: false
@@ -39,7 +39,7 @@ jobs:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- name: Checkout code - name: Checkout code
uses: actions/checkout@93cb6efe18208431cddfb8368fd83d5badbf9bfd # v5.0.1 uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v6.0.0
with: with:
persist-credentials: false persist-credentials: false
@@ -135,7 +135,7 @@ jobs:
matrix_target: ${{ matrix.target }} matrix_target: ${{ matrix.target }}
steps: steps:
- name: Checkout code - name: Checkout code
uses: actions/checkout@93cb6efe18208431cddfb8368fd83d5badbf9bfd # v5.0.1 uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v6.0.0
with: with:
persist-credentials: false persist-credentials: false

View File

@@ -33,7 +33,7 @@ jobs:
env: env:
tag: ${{ github.event.client_payload.tag }} tag: ${{ github.event.client_payload.tag }}
steps: steps:
- uses: actions/checkout@93cb6efe18208431cddfb8368fd83d5badbf9bfd # v5.0.1 - uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v6.0.0
with: with:
persist-credentials: false persist-credentials: false
@@ -169,7 +169,7 @@ jobs:
matrix_target: ${{ matrix.target }} matrix_target: ${{ matrix.target }}
tag: ${{ github.event.client_payload.tag }} tag: ${{ github.event.client_payload.tag }}
steps: steps:
- uses: actions/checkout@93cb6efe18208431cddfb8368fd83d5badbf9bfd # v5.0.1 - uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v6.0.0
with: with:
persist-credentials: false persist-credentials: false

View File

@@ -17,7 +17,7 @@ jobs:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- name: 'Checkout Repository' - name: 'Checkout Repository'
uses: actions/checkout@93cb6efe18208431cddfb8368fd83d5badbf9bfd # v5.0.1 uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v6.0.0
with: with:
persist-credentials: false persist-credentials: false

View File

@@ -17,7 +17,7 @@ jobs:
id-token: write # For trusted publishing id-token: write # For trusted publishing
steps: steps:
- name: Checkout repository - name: Checkout repository
uses: actions/checkout@93cb6efe18208431cddfb8368fd83d5badbf9bfd # v5 uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v6
with: with:
fetch-depth: 0 fetch-depth: 0
persist-credentials: false persist-credentials: false
@@ -53,7 +53,7 @@ jobs:
cancel-in-progress: false cancel-in-progress: false
steps: steps:
- name: Checkout repository - name: Checkout repository
uses: actions/checkout@93cb6efe18208431cddfb8368fd83d5badbf9bfd # v5 uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v6
with: with:
fetch-depth: 0 fetch-depth: 0
persist-credentials: false persist-credentials: false

View File

@@ -15,7 +15,7 @@ jobs:
matrix: matrix:
target: [x86_64, x86, aarch64] target: [x86_64, x86, aarch64]
steps: steps:
- uses: actions/checkout@93cb6efe18208431cddfb8368fd83d5badbf9bfd # v5.0.1 - uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v6.0.0
with: with:
persist-credentials: false persist-credentials: false
@@ -37,7 +37,7 @@ jobs:
matrix: matrix:
target: [x64, x86] target: [x64, x86]
steps: steps:
- uses: actions/checkout@93cb6efe18208431cddfb8368fd83d5badbf9bfd # v5.0.1 - uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v6.0.0
with: with:
persist-credentials: false persist-credentials: false
@@ -58,7 +58,7 @@ jobs:
matrix: matrix:
target: [x86_64, aarch64] target: [x86_64, aarch64]
steps: steps:
- uses: actions/checkout@93cb6efe18208431cddfb8368fd83d5badbf9bfd # v5.0.1 - uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v6.0.0
with: with:
persist-credentials: false persist-credentials: false
@@ -76,7 +76,7 @@ jobs:
sdist: sdist:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- uses: actions/checkout@93cb6efe18208431cddfb8368fd83d5badbf9bfd # v5.0.1 - uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v6.0.0
with: with:
persist-credentials: false persist-credentials: false

View File

@@ -36,7 +36,7 @@ jobs:
steps: steps:
- name: "Checkout code" - name: "Checkout code"
uses: actions/checkout@93cb6efe18208431cddfb8368fd83d5badbf9bfd # v5.0.1 uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v6.0.0
with: with:
persist-credentials: false persist-credentials: false

53
Cargo.lock generated
View File

@@ -272,9 +272,9 @@ checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6"
[[package]] [[package]]
name = "base64ct" name = "base64ct"
version = "1.7.3" version = "1.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "89e25b6adfb930f02d1981565a6e5d9c547ac15a96606256d3b59040e5cd4ca3" checksum = "55248b47b0caf0546f7988906588779981c43bb1bc9d0c44087278f80cdb44ba"
[[package]] [[package]]
name = "bitflags" name = "bitflags"
@@ -393,6 +393,16 @@ dependencies = [
"clap_derive", "clap_derive",
] ]
[[package]]
name = "clap-cargo"
version = "0.18.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "936551935c8258754bb8216aec040957d261f977303754b9bf1a213518388006"
dependencies = [
"anstyle",
"clap",
]
[[package]] [[package]]
name = "clap_builder" name = "clap_builder"
version = "4.5.53" version = "4.5.53"
@@ -807,13 +817,12 @@ dependencies = [
[[package]] [[package]]
name = "etcetera" name = "etcetera"
version = "0.10.0" version = "0.11.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "26c7b13d0780cb82722fd59f6f57f925e143427e4a75313a6c77243bf5326ae6" checksum = "de48cc4d1c1d97a20fd819def54b890cadde72ed3ad0c614822a0a433361be96"
dependencies = [ dependencies = [
"cfg-if", "cfg-if",
"home", "windows-sys 0.61.2",
"windows-sys 0.59.0",
] ]
[[package]] [[package]]
@@ -1069,9 +1078,9 @@ checksum = "0cc23270f6e1808e30a928bdc84dea0b9b4136a8bc82338574f23baf47bbd280"
[[package]] [[package]]
name = "globset" name = "globset"
version = "0.4.16" version = "0.4.18"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "54a1028dfc5f5df5da8a56a73e6c153c9a9708ec57232470703592a3f18e49f5" checksum = "52dfc19153a48bde0cbd630453615c8151bce3a5adfac7a0aebfbf0a1e1f57e3"
dependencies = [ dependencies = [
"aho-corasick", "aho-corasick",
"bstr", "bstr",
@@ -1118,9 +1127,9 @@ checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1"
[[package]] [[package]]
name = "hashbrown" name = "hashbrown"
version = "0.16.0" version = "0.16.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5419bdc4f6a9207fbeba6d11b604d481addf78ecd10c11ad51e76c2f6482748d" checksum = "841d1cc9bed7f9236f321df977030373f4a4163ae1a7dbfe1a51a2c1a51d9100"
[[package]] [[package]]
name = "heck" name = "heck"
@@ -1140,15 +1149,6 @@ version = "0.4.3"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70"
[[package]]
name = "home"
version = "0.5.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "589533453244b0995c858700322199b2becb13b627df2851f64a2775d024abcf"
dependencies = [
"windows-sys 0.59.0",
]
[[package]] [[package]]
name = "http" name = "http"
version = "1.3.1" version = "1.3.1"
@@ -1380,9 +1380,9 @@ dependencies = [
[[package]] [[package]]
name = "ignore" name = "ignore"
version = "0.4.23" version = "0.4.25"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6d89fd380afde86567dfba715db065673989d6253f42b88179abd3eae47bda4b" checksum = "d3d782a365a015e0f5c04902246139249abf769125006fbe7649e2ee88169b4a"
dependencies = [ dependencies = [
"crossbeam-deque", "crossbeam-deque",
"globset", "globset",
@@ -1402,12 +1402,12 @@ checksum = "964de6e86d545b246d84badc0fef527924ace5134f30641c203ef52ba83f58d5"
[[package]] [[package]]
name = "indexmap" name = "indexmap"
version = "2.12.0" version = "2.12.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6717a8d2a5a929a1a2eb43a12812498ed141a0bcfb7e8f7844fbdbe4303bba9f" checksum = "0ad4bb2b565bca0645f4d68c5c9af97fba094e9791da685bf83cb5f3ce74acf2"
dependencies = [ dependencies = [
"equivalent", "equivalent",
"hashbrown 0.16.0", "hashbrown 0.16.1",
"serde", "serde",
"serde_core", "serde_core",
] ]
@@ -2966,9 +2966,9 @@ checksum = "df8b2b54733674ad286d16267dcfc7a71ed5c776e4ac7aa3c3e2561f7c637bf2"
name = "topgrade" name = "topgrade"
version = "16.4.2" version = "16.4.2"
dependencies = [ dependencies = [
"base64ct",
"chrono", "chrono",
"clap", "clap",
"clap-cargo",
"clap_complete", "clap_complete",
"clap_mangen", "clap_mangen",
"color-eyre", "color-eyre",
@@ -2976,9 +2976,6 @@ dependencies = [
"etcetera", "etcetera",
"futures", "futures",
"glob", "glob",
"globset",
"home",
"ignore",
"indexmap", "indexmap",
"is_elevated", "is_elevated",
"jetbrains-toolbox-updater", "jetbrains-toolbox-updater",

View File

@@ -5,19 +5,18 @@ categories = ["os"]
keywords = ["upgrade", "update"] keywords = ["upgrade", "update"]
license = "GPL-3.0-or-later" license = "GPL-3.0-or-later"
repository = "https://github.com/topgrade-rs/topgrade" repository = "https://github.com/topgrade-rs/topgrade"
rust-version = "1.84.1" rust-version = "1.87.0"
version = "16.4.2" version = "16.4.2"
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 = "2024"
readme = "README.md" readme = "README.md"
[dependencies] [dependencies]
home = "=0.5.11" etcetera = "~0.11.0"
etcetera = "=0.10.0"
serde = { version = "~1.0", features = ["derive"] } serde = { version = "~1.0", features = ["derive"] }
toml = { version = "=0.9.8", features = ["preserve_order"] } toml = { version = "~0.9.8", features = ["preserve_order"] }
which_crate = { version = "~8.0", package = "which" } which_crate = { version = "~8.0", package = "which" }
shellexpand = "~3.1" shellexpand = "~3.1"
clap = { version = "~4.5", features = ["cargo", "derive"] } clap = { version = "~4.5", features = ["cargo", "derive"] }
@@ -47,10 +46,7 @@ sys-locale = "0.3.1"
jetbrains-toolbox-updater = "5.0.0" jetbrains-toolbox-updater = "5.0.0"
indexmap = { version = "2.9.0", features = ["serde"] } indexmap = { version = "2.9.0", features = ["serde"] }
serde_json = "1.0.145" serde_json = "1.0.145"
# Temporary transitive dependency pins clap-cargo = "0.18.0"
ignore = "=0.4.23"
globset = "=0.4.16"
base64ct = "<1.8.0"
[patch.crates-io] [patch.crates-io]
mac-notification-sys = { git = "https://github.com/h4llow3En/mac-notification-sys" } mac-notification-sys = { git = "https://github.com/h4llow3En/mac-notification-sys" }
@@ -64,7 +60,7 @@ git = "*"
[package.metadata.deb] [package.metadata.deb]
name = "topgrade" name = "topgrade"
maintainer = "Chris Gelatt <kreeblah@gmail.com>" maintainer = "Chris Gelatt <kreeblah@gmail.com>"
copyright = "2024, Topgrade Team" copyright = "2025, Topgrade Team"
license-file = ["LICENSE", "0"] license-file = ["LICENSE", "0"]
depends = "$auto" depends = "$auto"
extended-description = "Keeping your system up to date usually involves invoking multiple package managers. This results in big, non-portable shell one-liners saved in your shell. To remedy this, Topgrade detects which tools you use and runs the appropriate commands to update them." extended-description = "Keeping your system up to date usually involves invoking multiple package managers. This results in big, non-portable shell one-liners saved in your shell. To remedy this, Topgrade detects which tools you use and runs the appropriate commands to update them."

View File

@@ -3,10 +3,10 @@
<img alt="Topgrade" src="doc/topgrade_transparent.png" width="850px"> <img alt="Topgrade" src="doc/topgrade_transparent.png" width="850px">
</h1> </h1>
<a href="https://github.com/topgrade-rs/topgrade/releases"><img alt="GitHub Release" src="https://img.shields.io/github/release/topgrade-rs/topgrade.svg"></a> <a href="https://github.com/topgrade-rs/topgrade/releases"><img alt="GitHub Release" src="https://img.shields.io/github/release/topgrade-rs/topgrade.svg"></a>
<a href="https://crates.io/crates/topgrade"><img alt="crates.io" src="https://img.shields.io/crates/v/topgrade.svg"></a> <a href="https://crates.io/crates/topgrade"><img alt="crates.io" src="https://img.shields.io/crates/v/topgrade.svg"></a>
<a href="https://aur.archlinux.org/packages/topgrade"><img alt="AUR" src="https://img.shields.io/aur/version/topgrade.svg"></a> <a href="https://aur.archlinux.org/packages/topgrade"><img alt="AUR" src="https://img.shields.io/aur/version/topgrade.svg"></a>
<a href="https://formulae.brew.sh/formula/topgrade"><img alt="Homebrew" src="https://img.shields.io/homebrew/v/topgrade.svg"></a> <a href="https://formulae.brew.sh/formula/topgrade"><img alt="Homebrew" src="https://img.shields.io/homebrew/v/topgrade.svg"></a>
<img alt="Demo" src="doc/topgrade_demo.gif"> <img alt="Demo" src="doc/topgrade_demo.gif">
</div> </div>
@@ -37,6 +37,8 @@ To remedy this, **Topgrade** detects which tools you use and runs the appropriat
- Windows ([Winget](https://learn.microsoft.com/en-us/windows/package-manager/winget/)): [ - Windows ([Winget](https://learn.microsoft.com/en-us/windows/package-manager/winget/)): [
`winget install --id=topgrade-rs.topgrade -e`](https://winstall.app/apps/topgrade-rs.topgrade) `winget install --id=topgrade-rs.topgrade -e`](https://winstall.app/apps/topgrade-rs.topgrade)
- macOS or Linux ([Homebrew](https://brew.sh/)): [`brew install topgrade`](https://formulae.brew.sh/formula/topgrade) - macOS or Linux ([Homebrew](https://brew.sh/)): [`brew install topgrade`](https://formulae.brew.sh/formula/topgrade)
- Fedora/RHEL/AlmaLinux/CentOS-Stream ([Copr](https://copr.fedorainfracloud.org/)): [
`sudo dnf copr enable lilay/topgrade && sudo dnf install topgrade`](https://copr.fedorainfracloud.org/coprs/lilay/topgrade/)
### Community-maintained ### Community-maintained
@@ -46,8 +48,6 @@ To remedy this, **Topgrade** detects which tools you use and runs the appropriat
`scoop bucket add main && scoop install main/topgrade`](https://scoop.sh/#/apps?q=topgrade) `scoop bucket add main && scoop install main/topgrade`](https://scoop.sh/#/apps?q=topgrade)
- macOS ([MacPorts](https://www.macports.org/)): [ - macOS ([MacPorts](https://www.macports.org/)): [
`sudo port install topgrade`](https://ports.macports.org/port/topgrade/) `sudo port install topgrade`](https://ports.macports.org/port/topgrade/)
- Fedora ([Copr](https://copr.fedorainfracloud.org/)): [
`dnf copr enable lilay/topgrade && dnf install topgrade`](https://copr.fedorainfracloud.org/coprs/lilay/topgrade/)
- NixOS or Nix (nixpkgs): [topgrade](https://search.nixos.org/packages?show=topgrade) - NixOS or Nix (nixpkgs): [topgrade](https://search.nixos.org/packages?show=topgrade)
- Void Linux: [`sudo xbps-install -S topgrade`](https://voidlinux.org/packages/?arch=x86_64&q=topgrade) - Void Linux: [`sudo xbps-install -S topgrade`](https://voidlinux.org/packages/?arch=x86_64&q=topgrade)

View File

@@ -291,6 +291,20 @@
# (default: false) # (default: false)
# exclude_encrypted = false # exclude_encrypted = false
[mise]
# Upgrades to the latest version available, bumping the version in mise.toml
# (default: false)
# bump = false
# Number of jobs to run in parallel
# (default: 4)
# jobs = 4
# Run interactively
# (default: false)
# interactive = false
[npm] [npm]
# Use sudo if the NPM directory isn't owned by the current user # Use sudo if the NPM directory isn't owned by the current user
# use_sudo = true # use_sudo = true

View File

@@ -694,6 +694,14 @@ _version: 2
zh_CN: "不是专用的 macOS brew" zh_CN: "不是专用的 macOS brew"
zh_TW: "不是專門的 macOS brew" zh_TW: "不是專門的 macOS brew"
de: "Kein angepasstes Brew für macOS" de: "Kein angepasstes Brew für macOS"
"Homebrew cask support on Linux requires Homebrew 4.5.0 or later (found {version})":
en: "Homebrew cask support on Linux requires Homebrew 4.5.0 or later (found %{version})"
lt: "Homebrew cask palaikymas Linux sistemoje reikalauja Homebrew 4.5.0 arba naujesnes versijos (rasta %{version})"
es: "El soporte de cask de Homebrew en Linux requiere Homebrew 4.5.0 o posterior (encontrado %{version})"
fr: "Le support de cask Homebrew sur Linux nécessite Homebrew 4.5.0 ou supérieur (trouvé %{version})"
zh_CN: "Linux 上的 Homebrew cask 支持需要 Homebrew 4.5.0 或更高版本(找到 %{version}"
zh_TW: "Linux 上的 Homebrew cask 支援需要 Homebrew 4.5.0 或更高版本(找到 %{version}"
de: "Homebrew-Cask-Unterstützung unter Linux erfordert Homebrew 4.5.0 oder höher (gefunden %{version})"
"Guix Pull Failed, Skipping": "Guix Pull Failed, Skipping":
en: "Guix Pull Failed, Skipping" en: "Guix Pull Failed, Skipping"
lt: "Guix traukti nepavyko, praleidžiama" lt: "Guix traukti nepavyko, praleidžiama"

View File

@@ -5,13 +5,20 @@ build-backend = "maturin"
[project] [project]
name = "topgrade" name = "topgrade"
dynamic = ["version"] dynamic = ["version"]
description = "Upgrade all the things"
readme = "README.md"
license = "GPL-3.0-or-later"
requires-python = ">=3.7" requires-python = ">=3.7"
classifiers = [ classifiers = [
"License :: OSI Approved :: GNU General Public License v3 (GPLv3)",
"Programming Language :: Rust", "Programming Language :: Rust",
"Programming Language :: Python :: Implementation :: CPython", "Programming Language :: Python :: Implementation :: CPython",
"Programming Language :: Python :: Implementation :: PyPy", "Programming Language :: Python :: Implementation :: PyPy",
] ]
urls.bugs = "https://github.com/topgrade-rs/topgrade/issues"
urls.homepage = "https://github.com/topgrade-rs/topgrade"
[tool.maturin] [tool.maturin]
bindings = "bin" bindings = "bin"

View File

@@ -1,2 +1,2 @@
[toolchain] [toolchain]
channel = "1.84.1" channel = "1.87.0"

View File

@@ -4,17 +4,17 @@
//! 1. The Topgrade being executed is a new major release //! 1. The Topgrade being executed is a new major release
//! 2. This is the first launch of that major release //! 2. This is the first launch of that major release
use crate::terminal::print_separator;
#[cfg(windows)] #[cfg(windows)]
use crate::WINDOWS_DIRS; use crate::WINDOWS_DIRS;
#[cfg(unix)] #[cfg(unix)]
use crate::XDG_DIRS; use crate::XDG_DIRS;
use crate::terminal::print_separator;
use color_eyre::eyre::Result; use color_eyre::eyre::Result;
use etcetera::base_strategy::BaseStrategy; use etcetera::base_strategy::BaseStrategy;
use rust_i18n::t; use rust_i18n::t;
use std::{ use std::{
env::var, env::var,
fs::{read_to_string, OpenOptions}, fs::{OpenOptions, read_to_string},
io::Write, io::Write,
path::PathBuf, path::PathBuf,
str::FromStr, str::FromStr,

View File

@@ -5,8 +5,8 @@ use std::process::Child;
use std::process::{Command, ExitStatus, Output}; use std::process::{Command, ExitStatus, Output};
use color_eyre::eyre; use color_eyre::eyre;
use color_eyre::eyre::eyre;
use color_eyre::eyre::Context; use color_eyre::eyre::Context;
use color_eyre::eyre::eyre;
use crate::error::TopgradeError; use crate::error::TopgradeError;

View File

@@ -1,6 +1,6 @@
#![allow(dead_code)] #![allow(dead_code)]
use std::fs::{write, File}; use std::fs::{File, write};
use std::io::Write; use std::io::Write;
use std::path::{Path, PathBuf}; use std::path::{Path, PathBuf};
use std::process::Command; use std::process::Command;
@@ -173,6 +173,15 @@ pub struct Chezmoi {
exclude_encrypted: Option<bool>, exclude_encrypted: Option<bool>,
} }
#[derive(Deserialize, Default, Debug, Merge)]
#[serde(deny_unknown_fields)]
#[allow(clippy::upper_case_acronyms)]
pub struct Mise {
bump: Option<bool>,
interactive: Option<bool>,
jobs: Option<u32>,
}
#[derive(Deserialize, Default, Debug, Merge)] #[derive(Deserialize, Default, Debug, Merge)]
#[serde(deny_unknown_fields)] #[serde(deny_unknown_fields)]
#[allow(clippy::upper_case_acronyms)] #[allow(clippy::upper_case_acronyms)]
@@ -471,6 +480,9 @@ pub struct ConfigFile {
#[merge(strategy = crate::utils::merge_strategies::inner_merge_opt)] #[merge(strategy = crate::utils::merge_strategies::inner_merge_opt)]
chezmoi: Option<Chezmoi>, chezmoi: Option<Chezmoi>,
#[merge(strategy = crate::utils::merge_strategies::inner_merge_opt)]
mise: Option<Mise>,
#[merge(strategy = crate::utils::merge_strategies::inner_merge_opt)] #[merge(strategy = crate::utils::merge_strategies::inner_merge_opt)]
yarn: Option<Yarn>, yarn: Option<Yarn>,
@@ -717,7 +729,7 @@ impl ConfigFile {
// TODO: i18n of clap currently not easily possible. Waiting for https://github.com/clap-rs/clap/issues/380 // TODO: i18n of clap currently not easily possible. Waiting for https://github.com/clap-rs/clap/issues/380
// Tracking issue for i18n: https://github.com/topgrade-rs/topgrade/issues/859 // Tracking issue for i18n: https://github.com/topgrade-rs/topgrade/issues/859
#[derive(Parser, Debug)] #[derive(Parser, Debug)]
#[command(name = "topgrade", version)] #[command(name = "topgrade", version, styles = clap_cargo::style::CLAP_STYLING)]
pub struct CommandLineArgs { pub struct CommandLineArgs {
/// Edit the configuration file /// Edit the configuration file
#[arg(long = "edit-config")] #[arg(long = "edit-config")]
@@ -1804,6 +1816,26 @@ impl Config {
.unwrap_or(false) .unwrap_or(false)
} }
pub fn mise_bump(&self) -> bool {
self.config_file
.mise
.as_ref()
.and_then(|mise| mise.bump)
.unwrap_or(false)
}
pub fn mise_jobs(&self) -> u32 {
self.config_file.mise.as_ref().and_then(|mise| mise.jobs).unwrap_or(4)
}
pub fn mise_interactive(&self) -> bool {
self.config_file
.mise
.as_ref()
.and_then(|mise| mise.interactive)
.unwrap_or(false)
}
pub fn vscode_profile(&self) -> Option<&str> { pub fn vscode_profile(&self) -> Option<&str> {
let vscode_cfg = self.config_file.vscode.as_ref()?; let vscode_cfg = self.config_file.vscode.as_ref()?;
let profile = vscode_cfg.profile.as_ref()?; let profile = vscode_cfg.profile.as_ref()?;

View File

@@ -1,6 +1,6 @@
//! SIGINT handling in Unix systems. //! SIGINT handling in Unix systems.
use crate::ctrlc::interrupted::set_interrupted; use crate::ctrlc::interrupted::set_interrupted;
use nix::sys::signal::{sigaction, SaFlags, SigAction, SigHandler, SigSet, Signal}; use nix::sys::signal::{SaFlags, SigAction, SigHandler, SigSet, Signal, sigaction};
/// Handle SIGINT. Set the interruption flag. /// Handle SIGINT. Set the interruption flag.
extern "C" fn handle_sigint(_: i32) { extern "C" fn handle_sigint(_: i32) {

View File

@@ -1,8 +1,8 @@
//! A stub for Ctrl + C handling. //! A stub for Ctrl + C handling.
use crate::ctrlc::interrupted::set_interrupted; use crate::ctrlc::interrupted::set_interrupted;
use tracing::error; use tracing::error;
use windows::Win32::System::Console::{CTRL_C_EVENT, SetConsoleCtrlHandler};
use windows::core::BOOL; use windows::core::BOOL;
use windows::Win32::System::Console::{SetConsoleCtrlHandler, CTRL_C_EVENT};
extern "system" fn handler(ctrl_type: u32) -> BOOL { extern "system" fn handler(ctrl_type: u32) -> BOOL {
match ctrl_type { match ctrl_type {

View File

@@ -7,7 +7,7 @@ use std::process::{Child, Command, ExitStatus, Output};
use color_eyre::eyre::Result; use color_eyre::eyre::Result;
use rust_i18n::t; use rust_i18n::t;
use tracing::{debug, enabled, Level}; use tracing::{Level, debug, enabled};
use crate::command::CommandExt; use crate::command::CommandExt;
use crate::error::DryRun; use crate::error::DryRun;

View File

@@ -1,6 +1,7 @@
#![allow(clippy::cognitive_complexity)] #![allow(clippy::cognitive_complexity)]
use std::env; use std::env;
use std::env::home_dir;
use std::io; use std::io;
use std::path::PathBuf; use std::path::PathBuf;
use std::process::exit; use std::process::exit;
@@ -8,7 +9,7 @@ use std::time::Duration;
use crate::breaking_changes::{first_run_of_major_release, print_breaking_changes, should_skip, write_keep_file}; use crate::breaking_changes::{first_run_of_major_release, print_breaking_changes, should_skip, write_keep_file};
use clap::CommandFactory; use clap::CommandFactory;
use clap::{crate_version, Parser}; use clap::{Parser, crate_version};
use color_eyre::eyre::Context; use color_eyre::eyre::Context;
use color_eyre::eyre::Result; use color_eyre::eyre::Result;
use console::Key; use console::Key;
@@ -48,7 +49,7 @@ mod sudo;
mod terminal; mod terminal;
mod utils; mod utils;
pub(crate) static HOME_DIR: LazyLock<PathBuf> = LazyLock::new(|| home::home_dir().expect("No home directory")); pub(crate) static HOME_DIR: LazyLock<PathBuf> = LazyLock::new(|| home_dir().expect("No home directory"));
#[cfg(unix)] #[cfg(unix)]
pub(crate) static XDG_DIRS: LazyLock<Xdg> = LazyLock::new(|| Xdg::new().expect("No home directory")); pub(crate) static XDG_DIRS: LazyLock<Xdg> = LazyLock::new(|| Xdg::new().expect("No home directory"));
@@ -98,7 +99,7 @@ fn run() -> Result<()> {
let mut parts = env.split('='); let mut parts = env.split('=');
let var = parts.next().unwrap(); let var = parts.next().unwrap();
let value = parts.next().unwrap(); let value = parts.next().unwrap();
env::set_var(var, value); unsafe { env::set_var(var, value) };
} }
if opt.edit_config() { if opt.edit_config() {
@@ -321,11 +322,7 @@ fn run() -> Result<()> {
); );
} }
if failed { if failed { Err(StepFailed.into()) } else { Ok(()) }
Err(StepFailed.into())
} else {
Ok(())
}
} }
fn main() { fn main() {

View File

@@ -9,7 +9,7 @@ use crate::ctrlc;
use crate::error::{DryRun, MissingSudo, SkipStep}; use crate::error::{DryRun, MissingSudo, SkipStep};
use crate::execution_context::ExecutionContext; use crate::execution_context::ExecutionContext;
use crate::step::Step; use crate::step::Step;
use crate::terminal::{print_error, print_warning, should_retry, ShouldRetry}; use crate::terminal::{ShouldRetry, print_error, print_warning, should_retry};
pub enum StepResult { pub enum StepResult {
Success, Success,

View File

@@ -1,14 +1,14 @@
use std::env; use std::env;
#[cfg(unix)] #[cfg(unix)]
use std::os::unix::process::CommandExt as _; use std::os::unix::process::CommandExt as _;
use std::process::Command;
#[cfg(windows)] #[cfg(windows)]
use std::process::exit; use std::process::exit;
use std::process::Command;
use crate::step::Step; use crate::step::Step;
use color_eyre::eyre::Result;
#[cfg(unix)] #[cfg(unix)]
use color_eyre::eyre::bail; use color_eyre::eyre::bail;
use color_eyre::eyre::Result;
use rust_i18n::t; 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;

View File

@@ -225,7 +225,7 @@ impl Step {
Bin => runner.execute(*self, "bin", || generic::bin_update(ctx))?, Bin => runner.execute(*self, "bin", || generic::bin_update(ctx))?,
Bob => runner.execute(*self, "Bob", || generic::run_bob(ctx))?, Bob => runner.execute(*self, "Bob", || generic::run_bob(ctx))?,
BrewCask => { BrewCask => {
#[cfg(target_os = "macos")] #[cfg(any(target_os = "linux", target_os = "macos"))]
runner.execute(*self, "Brew Cask", || unix::run_brew_cask(ctx, unix::BrewVariant::Path))?; runner.execute(*self, "Brew Cask", || unix::run_brew_cask(ctx, unix::BrewVariant::Path))?;
#[cfg(target_os = "macos")] #[cfg(target_os = "macos")]
runner.execute(*self, "Brew Cask (Intel)", || { runner.execute(*self, "Brew Cask (Intel)", || {
@@ -750,6 +750,7 @@ pub(crate) fn default_steps() -> Vec<Step> {
Restarts, Restarts,
Flatpak, Flatpak,
BrewFormula, BrewFormula,
BrewCask,
Lure, Lure,
Waydroid, Waydroid,
AutoCpufreq, AutoCpufreq,

View File

@@ -6,7 +6,7 @@ use std::process::Command;
use color_eyre::eyre::Context; use color_eyre::eyre::Context;
use color_eyre::eyre::Result; use color_eyre::eyre::Result;
use color_eyre::eyre::{eyre, OptionExt}; use color_eyre::eyre::{OptionExt, eyre};
use tracing::{debug, error, warn}; use tracing::{debug, error, warn};
use wildmatch::WildMatch; use wildmatch::WildMatch;

View File

@@ -10,7 +10,7 @@ use crate::command::CommandExt;
use crate::execution_context::ExecutionContext; use crate::execution_context::ExecutionContext;
use crate::step::Step; use crate::step::Step;
use crate::terminal::print_separator; use crate::terminal::print_separator;
use crate::utils::{require, require_option, PathExt}; use crate::utils::{PathExt, require, require_option};
const EMACS_UPGRADE: &str = include_str!("emacs.el"); const EMACS_UPGRADE: &str = include_str!("emacs.el");
#[cfg(windows)] #[cfg(windows)]

View File

@@ -1,7 +1,7 @@
use color_eyre::eyre::Context; use color_eyre::eyre::Context;
use color_eyre::eyre::Result; use color_eyre::eyre::Result;
use color_eyre::eyre::{eyre, OptionExt}; use color_eyre::eyre::{OptionExt, eyre};
use jetbrains_toolbox_updater::{find_jetbrains_toolbox, update_jetbrains_toolbox, FindError}; use jetbrains_toolbox_updater::{FindError, find_jetbrains_toolbox, update_jetbrains_toolbox};
use regex::bytes::Regex; use regex::bytes::Regex;
use rust_i18n::t; use rust_i18n::t;
use semver::Version; use semver::Version;
@@ -16,6 +16,7 @@ use std::{fs, io::Write};
use tempfile::tempfile_in; use tempfile::tempfile_in;
use tracing::{debug, error, warn}; use tracing::{debug, error, warn};
use crate::HOME_DIR;
use crate::command::{CommandExt, Utf8Output}; use crate::command::{CommandExt, Utf8Output};
use crate::execution_context::ExecutionContext; use crate::execution_context::ExecutionContext;
use crate::executor::ExecutorOutput; use crate::executor::ExecutorOutput;
@@ -23,8 +24,7 @@ use crate::output_changed_message;
use crate::step::Step; use crate::step::Step;
use crate::sudo::SudoExecuteOpts; use crate::sudo::SudoExecuteOpts;
use crate::terminal::{print_separator, shell}; use crate::terminal::{print_separator, shell};
use crate::utils::{check_is_python_2_or_shim, require, require_one, require_option, which, PathExt}; use crate::utils::{PathExt, check_is_python_2_or_shim, require, require_one, require_option, which};
use crate::HOME_DIR;
use crate::{ use crate::{
error::{SkipStep, StepFailed, TopgradeError}, error::{SkipStep, StepFailed, TopgradeError},
terminal::print_warning, terminal::print_warning,
@@ -65,7 +65,9 @@ pub fn run_cargo_update(ctx: &ExecutionContext) -> Result<()> {
.or_else(|| cargo_dir.join("bin/cargo-install-update").if_exists()); .or_else(|| cargo_dir.join("bin/cargo-install-update").if_exists());
let Some(cargo_update) = cargo_update else { let Some(cargo_update) = cargo_update else {
let message = String::from("cargo-update isn't installed so Topgrade can't upgrade cargo packages.\nInstall cargo-update by running `cargo install cargo-update`"); 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());
}; };
@@ -81,7 +83,9 @@ pub fn run_cargo_update(ctx: &ExecutionContext) -> Result<()> {
if let Some(e) = cargo_cache { if let Some(e) = cargo_cache {
ctx.execute(e).args(["-a"]).status_checked()?; ctx.execute(e).args(["-a"]).status_checked()?;
} else { } 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`"); 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); print_warning(message);
} }
} }
@@ -542,7 +546,7 @@ fn run_vscode_compatible(variant: VSCodeVariant, ctx: &ExecutionContext) -> Resu
return Err(eyre!(output_changed_message!( return Err(eyre!(output_changed_message!(
&format!("{bin_name} --version"), &format!("{bin_name} --version"),
"No first line" "No first line"
))) )));
} }
}; };
@@ -1239,11 +1243,7 @@ pub fn run_helm_repo_update(ctx: &ExecutionContext) -> Result<()> {
}; };
} }
if success { if success { Ok(()) } else { Err(eyre!(StepFailed)) }
Ok(())
} else {
Err(eyre!(StepFailed))
}
} }
pub fn run_stew(ctx: &ExecutionContext) -> Result<()> { pub fn run_stew(ctx: &ExecutionContext) -> Result<()> {
@@ -1428,8 +1428,7 @@ pub fn run_poetry(ctx: &ExecutionContext) -> Result<()> {
.map_err(|e| SkipStep(format!("Could not find interpreter for {}: {}", poetry.display(), e)))?; .map_err(|e| SkipStep(format!("Could not find interpreter for {}: {}", poetry.display(), e)))?;
debug!("poetry interpreter: {:?}, args: {:?}", interp, interp_args); debug!("poetry interpreter: {:?}, args: {:?}", interp, interp_args);
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 mut command = Command::new(&interp); let mut command = Command::new(&interp);
if let Some(args) = interp_args { if let Some(args) = interp_args {
command.arg(args); command.arg(args);
@@ -1708,7 +1707,10 @@ fn run_jetbrains_ide_generic<const IS_JETBRAINS: bool>(ctx: &ExecutionContext, b
.code() .code()
.ok_or_eyre("Failed to get status code; was killed with signal")?; .ok_or_eyre("Failed to get status code; was killed with signal")?;
if status_code != 1 { if status_code != 1 {
return Err(eyre!("Expected status code 1 ('Only one instance of <IDE> can be run at a time.'), but found status code {}. Output: {output:?}", status_code)); return Err(eyre!(
"Expected status code 1 ('Only one instance of <IDE> can be run at a time.'), but found status code {}. Output: {output:?}",
status_code
));
} }
// Don't crash, but don't be silent either // Don't crash, but don't be silent either
warn!("{name} is already running, can't update it now."); warn!("{name} is already running, can't update it now.");

View File

@@ -4,10 +4,10 @@ use std::path::{Path, PathBuf};
use std::process::{Command, Output, Stdio}; use std::process::{Command, Output, Stdio};
use color_eyre::eyre::Context; use color_eyre::eyre::Context;
use color_eyre::eyre::{eyre, Result}; use color_eyre::eyre::{Result, eyre};
use console::style; use console::style;
use futures::stream::{iter, FuturesUnordered, StreamExt}; use futures::stream::{FuturesUnordered, StreamExt, iter};
use glob::{glob_with, MatchOptions}; use glob::{MatchOptions, glob_with};
use tokio::process::Command as AsyncCommand; use tokio::process::Command as AsyncCommand;
use tokio::runtime; use tokio::runtime;
use tracing::{debug, error}; use tracing::{debug, error};
@@ -17,8 +17,8 @@ use crate::execution_context::ExecutionContext;
use crate::step::Step; use crate::step::Step;
use crate::steps::emacs::Emacs; use crate::steps::emacs::Emacs;
use crate::terminal::print_separator; use crate::terminal::print_separator;
use crate::utils::{require, PathExt}; use crate::utils::{PathExt, require};
use crate::{error::SkipStep, terminal::print_warning, HOME_DIR}; use crate::{HOME_DIR, error::SkipStep, terminal::print_warning};
use etcetera::base_strategy::BaseStrategy; use etcetera::base_strategy::BaseStrategy;
use rust_i18n::t; use rust_i18n::t;

View File

@@ -14,7 +14,7 @@ use tracing::debug;
use crate::command::CommandExt; use crate::command::CommandExt;
use crate::terminal::{print_info, print_separator}; use crate::terminal::{print_info, print_separator};
use crate::utils::{require, PathExt}; use crate::utils::{PathExt, require};
use crate::{error::SkipStep, execution_context::ExecutionContext}; use crate::{error::SkipStep, execution_context::ExecutionContext};
enum NPMVariant { enum NPMVariant {
@@ -65,11 +65,7 @@ impl NPM {
/// If the “NPM” version is larger than 8.11.0, we use /// If the “NPM” version is larger than 8.11.0, we use
/// `--location=global`; otherwise, use `-g`. /// `--location=global`; otherwise, use `-g`.
fn global_location_arg(&self) -> &str { fn global_location_arg(&self) -> &str {
if self.is_npm_8() { if self.is_npm_8() { "--location=global" } else { "-g" }
"--location=global"
} else {
"-g"
}
} }
#[cfg(target_os = "linux")] #[cfg(target_os = "linux")]

View File

@@ -6,6 +6,7 @@ use ini::Ini;
use rust_i18n::t; use rust_i18n::t;
use tracing::{debug, warn}; use tracing::{debug, warn};
use crate::HOME_DIR;
use crate::command::CommandExt; use crate::command::CommandExt;
use crate::error::{SkipStep, TopgradeError}; use crate::error::{SkipStep, TopgradeError};
use crate::execution_context::ExecutionContext; use crate::execution_context::ExecutionContext;
@@ -14,8 +15,7 @@ use crate::steps::generic::is_wsl;
use crate::steps::os::archlinux; use crate::steps::os::archlinux;
use crate::sudo::SudoExecuteOpts; use crate::sudo::SudoExecuteOpts;
use crate::terminal::{print_separator, prompt_yesno}; use crate::terminal::{print_separator, prompt_yesno};
use crate::utils::{require, require_one, which, PathExt}; use crate::utils::{PathExt, require, require_one, which};
use crate::HOME_DIR;
static OS_RELEASE_PATH: &str = "/etc/os-release"; static OS_RELEASE_PATH: &str = "/etc/os-release";

View File

@@ -200,7 +200,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.last().map_or(true, |s| !s.contains("(Installed)")) && !releases_filtered.is_empty() { if releases_filtered.last().is_none_or(|s| !s.contains("(Installed)")) && !releases_filtered.is_empty() {
println!( println!(
"{} {}", "{} {}",
t!("New Xcode release detected:"), t!("New Xcode release detected:"),

View File

@@ -1,14 +1,14 @@
use color_eyre::eyre::Context; use color_eyre::eyre::Context;
use color_eyre::eyre::Result; use color_eyre::eyre::Result;
use color_eyre::eyre::{eyre, OptionExt}; use color_eyre::eyre::{OptionExt, eyre};
use etcetera::BaseStrategy; use etcetera::BaseStrategy;
use home;
use ini::Ini; use ini::Ini;
#[cfg(target_os = "linux")] #[cfg(target_os = "linux")]
use nix::unistd::Uid; use nix::unistd::Uid;
use regex::Regex; use regex::Regex;
use rust_i18n::t; use rust_i18n::t;
use semver::Version; use semver::Version;
use std::env::home_dir;
use std::ffi::OsStr; use std::ffi::OsStr;
use std::io::Write; use std::io::Write;
use std::os::unix::fs::MetadataExt; use std::os::unix::fs::MetadataExt;
@@ -20,10 +20,10 @@ use std::{env::var, path::Path};
use std::{fs, io}; use std::{fs, io};
use tracing::{debug, warn}; use tracing::{debug, warn};
use crate::XDG_DIRS;
use crate::command::CommandExt; use crate::command::CommandExt;
use crate::sudo::SudoExecuteOpts; use crate::sudo::SudoExecuteOpts;
use crate::XDG_DIRS; use crate::{HOME_DIR, output_changed_message};
use crate::{output_changed_message, HOME_DIR};
#[cfg(target_os = "linux")] #[cfg(target_os = "linux")]
use super::linux::Distribution; use super::linux::Distribution;
@@ -33,7 +33,7 @@ use crate::execution_context::ExecutionContext;
use crate::executor::Executor; use crate::executor::Executor;
use crate::step::Step; use crate::step::Step;
use crate::terminal::print_separator; use crate::terminal::print_separator;
use crate::utils::{require, PathExt}; use crate::utils::{PathExt, require};
#[cfg(any(target_os = "linux", target_os = "macos"))] #[cfg(any(target_os = "linux", target_os = "macos"))]
const INTEL_BREW: &str = "/usr/local/bin/brew"; const INTEL_BREW: &str = "/usr/local/bin/brew";
@@ -81,7 +81,6 @@ impl BrewVariant {
/// Execute an "internal" brew command, i.e. one that should always be run /// Execute an "internal" brew command, i.e. one that should always be run
/// even when dry-running. Basically just a wrapper around [`Command::new`] /// even when dry-running. Basically just a wrapper around [`Command::new`]
/// that uses `arch` to run using the correct architecture if needed. /// that uses `arch` to run using the correct architecture if needed.
#[cfg(target_os = "macos")]
fn execute_internal(self) -> Command { fn execute_internal(self) -> Command {
match self { match self {
BrewVariant::MacIntel if cfg!(target_arch = "aarch64") => { BrewVariant::MacIntel if cfg!(target_arch = "aarch64") => {
@@ -365,12 +364,48 @@ pub fn run_brew_formula(ctx: &ExecutionContext, variant: BrewVariant) -> Result<
Ok(()) Ok(())
} }
#[cfg(target_os = "macos")] #[cfg(any(target_os = "linux", target_os = "macos"))]
pub fn run_brew_cask(ctx: &ExecutionContext, variant: BrewVariant) -> Result<()> { pub fn run_brew_cask(ctx: &ExecutionContext, variant: BrewVariant) -> Result<()> {
let binary_name = require(variant.binary_name())?; let binary_name = require(variant.binary_name())?;
#[cfg(target_os = "macos")]
if variant.is_path() && !BrewVariant::is_macos_custom(binary_name) { if variant.is_path() && !BrewVariant::is_macos_custom(binary_name) {
return Err(SkipStep(t!("Not a custom brew for macOS").to_string()).into()); return Err(SkipStep(t!("Not a custom brew for macOS").to_string()).into());
} }
#[cfg(target_os = "linux")]
{
// Homebrew cask support was added in version 4.5.0
let version_output = Command::new(&binary_name).arg("--version").output_checked_utf8()?;
let version_line = version_output
.stdout
.lines()
.next()
.ok_or_else(|| eyre!(output_changed_message!("brew --version", "no output lines")))?;
let version_str = version_line.split_whitespace().nth(1).ok_or_else(|| {
eyre!(output_changed_message!(
"brew --version",
"Expected version after 'Homebrew'"
))
})?;
let version = Version::parse(version_str)
.wrap_err_with(|| output_changed_message!("brew --version", "Invalid version"))?;
if version < Version::new(4, 5, 0) {
return Err(SkipStep(
t!(
"Homebrew cask support on Linux requires Homebrew 4.5.0 or later (found {version})",
version = version
)
.to_string(),
)
.into());
}
}
print_separator(format!("{} - Cask", variant.step_title())); print_separator(format!("{} - Cask", variant.step_title()));
let cask_upgrade_exists = variant let cask_upgrade_exists = variant
@@ -491,8 +526,8 @@ pub fn run_nix(ctx: &ExecutionContext) -> Result<()> {
let nix = require("nix")?; let nix = require("nix")?;
let nix_channel = require("nix-channel")?; let nix_channel = require("nix-channel")?;
let nix_env = require("nix-env")?; let nix_env = require("nix-env")?;
// TODO: Is None possible here? // TODO: Is None possible here? Should we use HOME_DIR instead?
let profile_path = match home::home_dir() { let profile_path = match home_dir() {
Some(home) => XDG_DIRS Some(home) => XDG_DIRS
.state_dir() .state_dir()
.map(|d| d.join("nix/profile")) .map(|d| d.join("nix/profile"))
@@ -824,7 +859,23 @@ pub fn run_mise(ctx: &ExecutionContext) -> Result<()> {
} }
} }
ctx.execute(&mise).arg("upgrade").status_checked() let mut cmd = ctx.execute(&mise);
cmd.arg("upgrade");
if ctx.config().mise_interactive() {
cmd.arg("--interactive");
}
if ctx.config().mise_bump() {
cmd.arg("--bump");
}
if ctx.config().mise_jobs() != 4 {
cmd.args(["--jobs", &ctx.config().mise_jobs().to_string()]);
}
cmd.status_checked()
} }
pub fn run_home_manager(ctx: &ExecutionContext) -> Result<()> { pub fn run_home_manager(ctx: &ExecutionContext) -> Result<()> {

View File

@@ -254,11 +254,7 @@ pub fn microsoft_store(ctx: &ExecutionContext) -> Result<()> {
} }
let ret_val = output.stdout.trim(); let ret_val = output.stdout.trim();
debug!("Command return value: {}", ret_val); debug!("Command return value: {}", ret_val);
if ret_val == "0" { if ret_val == "0" { Ok(()) } else { Err(()) }
Ok(())
} else {
Err(())
}
})?; })?;
println!( println!(
"{}", "{}",

View File

@@ -1,15 +1,15 @@
use std::path::PathBuf; use std::path::PathBuf;
use std::process::Command; use std::process::Command;
use color_eyre::eyre::Result;
#[cfg(windows)] #[cfg(windows)]
use color_eyre::eyre::eyre; use color_eyre::eyre::eyre;
use color_eyre::eyre::Result;
use tracing::debug; use tracing::debug;
use crate::command::CommandExt; use crate::command::CommandExt;
use crate::execution_context::ExecutionContext; use crate::execution_context::ExecutionContext;
use crate::terminal; use crate::terminal;
use crate::utils::{which, PathExt}; use crate::utils::{PathExt, which};
pub struct Powershell { pub struct Powershell {
path: PathBuf, path: PathBuf,

View File

@@ -2,20 +2,20 @@ use std::env;
use std::path::PathBuf; use std::path::PathBuf;
use std::process::Command; use std::process::Command;
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 color_eyre::eyre::eyre;
use etcetera::base_strategy::BaseStrategy; use etcetera::base_strategy::BaseStrategy;
use crate::command::CommandExt; use crate::command::CommandExt;
use crate::config::TmuxConfig; use crate::config::TmuxConfig;
use crate::config::TmuxSessionMode; use crate::config::TmuxSessionMode;
use crate::terminal::print_separator; use crate::terminal::print_separator;
use crate::{HOME_DIR, XDG_DIRS};
use crate::{ use crate::{
execution_context::ExecutionContext, execution_context::ExecutionContext,
utils::{which, PathExt}, utils::{PathExt, which},
}; };
use crate::{HOME_DIR, XDG_DIRS};
use rust_i18n::t; use rust_i18n::t;
#[cfg(unix)] #[cfg(unix)]

View File

@@ -1,6 +1,6 @@
use crate::HOME_DIR;
use crate::command::CommandExt; use crate::command::CommandExt;
use crate::error::{SkipStep, TopgradeError}; use crate::error::{SkipStep, TopgradeError};
use crate::HOME_DIR;
use color_eyre::eyre::Result; use color_eyre::eyre::Result;
use etcetera::base_strategy::BaseStrategy; use etcetera::base_strategy::BaseStrategy;
@@ -8,7 +8,7 @@ use crate::executor::{Executor, ExecutorOutput};
use crate::terminal::print_separator; use crate::terminal::print_separator;
use crate::{ use crate::{
execution_context::ExecutionContext, execution_context::ExecutionContext,
utils::{require, PathExt}, utils::{PathExt, require},
}; };
use rust_i18n::t; use rust_i18n::t;
use std::path::PathBuf; use std::path::PathBuf;

View File

@@ -6,13 +6,13 @@ use color_eyre::eyre::Result;
use tracing::debug; use tracing::debug;
use walkdir::WalkDir; use walkdir::WalkDir;
use crate::HOME_DIR;
use crate::XDG_DIRS;
use crate::command::CommandExt; use crate::command::CommandExt;
use crate::execution_context::ExecutionContext; use crate::execution_context::ExecutionContext;
use crate::git::RepoStep; use crate::git::RepoStep;
use crate::terminal::print_separator; use crate::terminal::print_separator;
use crate::utils::{require, PathExt}; use crate::utils::{PathExt, require};
use crate::HOME_DIR;
use crate::XDG_DIRS;
use etcetera::base_strategy::BaseStrategy; use etcetera::base_strategy::BaseStrategy;
pub fn run_zr(ctx: &ExecutionContext) -> Result<()> { pub fn run_zr(ctx: &ExecutionContext) -> Result<()> {
@@ -162,7 +162,7 @@ pub fn run_oh_my_zsh(ctx: &ExecutionContext) -> Result<()> {
if let Ok(output) = res_env_zsh { if let Ok(output) = res_env_zsh {
let env_zsh = output.stdout; let env_zsh = output.stdout;
debug!("Oh-my-zsh: under SSH, setting ZSH={}", env_zsh); debug!("Oh-my-zsh: under SSH, setting ZSH={}", env_zsh);
env::set_var("ZSH", env_zsh); unsafe { env::set_var("ZSH", env_zsh) };
} }
} }

View File

@@ -4,10 +4,10 @@ use std::path::PathBuf;
#[cfg(windows)] #[cfg(windows)]
use color_eyre::eyre; use color_eyre::eyre;
#[cfg(windows)]
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;
#[cfg(windows)]
use color_eyre::eyre::eyre;
use rust_i18n::t; use rust_i18n::t;
use serde::Deserialize; use serde::Deserialize;
use strum::Display; use strum::Display;

View File

@@ -8,7 +8,7 @@ use std::time::Duration;
use chrono::{Local, Timelike}; use chrono::{Local, Timelike};
use color_eyre::eyre; use color_eyre::eyre;
use color_eyre::eyre::Context; use color_eyre::eyre::Context;
use console::{style, Key, Term}; use console::{Key, Term, style};
use notify_rust::{Notification, Timeout}; use notify_rust::{Notification, Timeout};
use rust_i18n::t; use rust_i18n::t;
use tracing::{debug, error}; use tracing::{debug, error};

View File

@@ -11,8 +11,8 @@ use tracing::{debug, error};
use tracing_subscriber::layer::SubscriberExt; use tracing_subscriber::layer::SubscriberExt;
use tracing_subscriber::reload::{Handle, Layer}; use tracing_subscriber::reload::{Handle, Layer};
use tracing_subscriber::util::SubscriberInitExt; use tracing_subscriber::util::SubscriberInitExt;
use tracing_subscriber::{fmt, Registry}; use tracing_subscriber::{EnvFilter, registry};
use tracing_subscriber::{registry, EnvFilter}; use tracing_subscriber::{Registry, fmt};
use crate::command::CommandExt; use crate::command::CommandExt;
use crate::config::DEFAULT_LOG_LEVEL; use crate::config::DEFAULT_LOG_LEVEL;
@@ -218,7 +218,7 @@ pub mod merge_strategies {
where where
T: Merge, T: Merge,
{ {
if let Some(ref mut left_inner) = left { if let Some(left_inner) = left {
if let Some(right_inner) = right { if let Some(right_inner) = right {
left_inner.merge(right_inner); left_inner.merge(right_inner);
} }
@@ -228,7 +228,7 @@ pub mod merge_strategies {
} }
pub fn commands_merge_opt(left: &mut Option<Commands>, right: Option<Commands>) { pub fn commands_merge_opt(left: &mut Option<Commands>, right: Option<Commands>) {
if let Some(ref mut left_inner) = left { if let Some(left_inner) = left {
if let Some(right_inner) = right { if let Some(right_inner) = right {
left_inner.extend(right_inner); left_inner.extend(right_inner);
} }