Compare commits
159 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
266adabd13 | ||
|
|
7d2e43f83b | ||
|
|
294a90a7c3 | ||
|
|
af5def1551 | ||
|
|
8c63ee6a18 | ||
|
|
ee8ae8623d | ||
|
|
222e6b55c0 | ||
|
|
2050a80665 | ||
|
|
e01be14041 | ||
|
|
dd6bc580fa | ||
|
|
22ef36a185 | ||
|
|
b57ceccbe1 | ||
|
|
e9d430a4e4 | ||
|
|
8a247fba95 | ||
|
|
5b6c31bd89 | ||
|
|
c316e2af69 | ||
|
|
7270aa96f0 | ||
|
|
dd823eb489 | ||
|
|
cb29305385 | ||
|
|
2dfa37dd0c | ||
|
|
b3d3284f18 | ||
|
|
73e3e133c6 | ||
|
|
9828af9f03 | ||
|
|
48aa6b5ac5 | ||
|
|
e5b3ed1461 | ||
|
|
5fad9f0ec6 | ||
|
|
f4a5507716 | ||
|
|
2ea9d1d6fd | ||
|
|
e393b1f90b | ||
|
|
2259e81bb0 | ||
|
|
65a30292a3 | ||
|
|
494eef3472 | ||
|
|
bee1e865b2 | ||
|
|
c92b049bbc | ||
|
|
c9985480fe | ||
|
|
e1b5b76d8e | ||
|
|
762a74f5f9 | ||
|
|
a7a2d8493e | ||
|
|
bc6538d209 | ||
|
|
93d841310e | ||
|
|
2ac679f17e | ||
|
|
9a3ef463f9 | ||
|
|
affc5fcd75 | ||
|
|
96bff5e974 | ||
|
|
e828e14fa5 | ||
|
|
4c6dc8ff82 | ||
|
|
75bd7c90d3 | ||
|
|
2aa3d94a98 | ||
|
|
f4ac809dff | ||
|
|
0dee534f84 | ||
|
|
ad9f2c2ccb | ||
|
|
a886d20a7b | ||
|
|
791993795a | ||
|
|
a2afdb821f | ||
|
|
47b51a8be0 | ||
|
|
7c7e7c3ce4 | ||
|
|
fec08a5ad1 | ||
|
|
3961ef61c8 | ||
|
|
84692da9a2 | ||
|
|
fb7ba52e39 | ||
|
|
898823abb2 | ||
|
|
ccefd0a43a | ||
|
|
98f0be61ed | ||
|
|
6bb1d54cb0 | ||
|
|
69a76e32b7 | ||
|
|
99d989d486 | ||
|
|
456d62224e | ||
|
|
b662fae11e | ||
|
|
0926bd2f6c | ||
|
|
3fb473ae95 | ||
|
|
603ed18a4c | ||
|
|
0307fdd296 | ||
|
|
c10dcdbfdb | ||
|
|
31d8e579c6 | ||
|
|
7b3fec0349 | ||
|
|
e32a58f6ff | ||
|
|
36cd726676 | ||
|
|
8dc08de628 | ||
|
|
0361954919 | ||
|
|
29a62575f4 | ||
|
|
547a6df2ae | ||
|
|
53d08cdf28 | ||
|
|
a033152c60 | ||
|
|
9472aaca7a | ||
|
|
6254b99e02 | ||
|
|
3d17bdb747 | ||
|
|
d2eeeb9129 | ||
|
|
1d626e0add | ||
|
|
9f4cb8c1b6 | ||
|
|
91fc5e3902 | ||
|
|
9048cd8f47 | ||
|
|
4f5e8a8836 | ||
|
|
29b05fa50f | ||
|
|
dbe1a5c988 | ||
|
|
b6c1290934 | ||
|
|
306ff3c7c5 | ||
|
|
0e43e0d7fc | ||
|
|
4da696321a | ||
|
|
a95dd1e037 | ||
|
|
012a6bbde3 | ||
|
|
32197f79f3 | ||
|
|
257d202646 | ||
|
|
c00365c19d | ||
|
|
3f9fe845e5 | ||
|
|
b166aae835 | ||
|
|
31f0097862 | ||
|
|
f78514dbd8 | ||
|
|
9fc5fe9798 | ||
|
|
6d14ac1693 | ||
|
|
b8ab573c00 | ||
|
|
75ac6808a1 | ||
|
|
6719ff93d8 | ||
|
|
6b8327faad | ||
|
|
85c8bd2277 | ||
|
|
23fff2a09f | ||
|
|
689db93c99 | ||
|
|
1114556661 | ||
|
|
f8c910a3c2 | ||
|
|
f18ae089ff | ||
|
|
4a64992054 | ||
|
|
9fefb47242 | ||
|
|
fc5cc3c43b | ||
|
|
27464b795e | ||
|
|
845558c1da | ||
|
|
31fe5aa452 | ||
|
|
b354e07ef3 | ||
|
|
50a74dac4b | ||
|
|
7558bbfe9b | ||
|
|
7518676ac9 | ||
|
|
b7b665ff48 | ||
|
|
1be941e815 | ||
|
|
d1b7eba44e | ||
|
|
38e2d5663a | ||
|
|
3db95a3e67 | ||
|
|
ef0a0d69bb | ||
|
|
4b3a3e74f8 | ||
|
|
2c4751c7b2 | ||
|
|
30941ed26d | ||
|
|
c7163b63db | ||
|
|
6e6b3dcbfe | ||
|
|
1d136a6635 | ||
|
|
0ee67d78ef | ||
|
|
7356b920d4 | ||
|
|
ce8a325c1f | ||
|
|
a2f57e4769 | ||
|
|
751f41bc5e | ||
|
|
fd406f0f82 | ||
|
|
801dddacd4 | ||
|
|
397a537eef | ||
|
|
0423c836eb | ||
|
|
3250337e70 | ||
|
|
9dcd7fffe2 | ||
|
|
30b727b138 | ||
|
|
b86d6981ab | ||
|
|
2bf6a2b100 | ||
|
|
3dc8d31d57 | ||
|
|
b308fb92c0 | ||
|
|
bc9746455e | ||
|
|
109a9c76e3 |
34
.github/ISSUE_TEMPLATE/bug_report.md
vendored
34
.github/ISSUE_TEMPLATE/bug_report.md
vendored
@@ -8,41 +8,41 @@ assignees: ''
|
|||||||
---
|
---
|
||||||
|
|
||||||
<!--
|
<!--
|
||||||
Thanks for taking the time to fill out this bug report!
|
Thanks for taking the time to fill out this bug report!
|
||||||
Please make sure to
|
Please make sure to
|
||||||
[search for existing issues](https://github.com/topgrade-rs/topgrade/issues)
|
[search for existing issues](https://github.com/topgrade-rs/topgrade/issues)
|
||||||
before filing a new one!
|
before filing a new one!
|
||||||
|
|
||||||
Questions labeled with `Optional` can be skipped.
|
Questions labeled with `Optional` can be skipped.
|
||||||
-->
|
-->
|
||||||
|
|
||||||
<!--
|
<!--
|
||||||
If you're here to report about a "No asset found" error, please make sure that
|
If you're here to report about a "No asset found" error, please make sure that
|
||||||
an hour has been passed since the last release was made.
|
an hour has been passed since the last release was made.
|
||||||
-->
|
-->
|
||||||
|
|
||||||
## Erroneous Behavior
|
## Erroneous Behavior
|
||||||
<!--
|
<!--
|
||||||
What actually happened?
|
What actually happened?
|
||||||
-->
|
-->
|
||||||
|
|
||||||
## Expected Behavior
|
## Expected Behavior
|
||||||
<!--
|
<!--
|
||||||
Describe the expected behavior
|
Describe the expected behavior
|
||||||
-->
|
-->
|
||||||
|
|
||||||
## Steps to reproduce
|
## Steps to reproduce
|
||||||
<!--
|
<!--
|
||||||
A minimal example to reproduce the issue
|
A minimal example to reproduce the issue
|
||||||
-->
|
-->
|
||||||
|
|
||||||
## Possible Cause (Optional)
|
## Possible Cause (Optional)
|
||||||
<!--
|
<!--
|
||||||
If you know the possible cause of the issue, please tell us.
|
If you know the possible cause of the issue, please tell us.
|
||||||
-->
|
-->
|
||||||
|
|
||||||
## Problem persists without calling from topgrade
|
## Problem persists without calling from topgrade
|
||||||
<!--
|
<!--
|
||||||
Execute the erroneous command directly to see if the problem persists
|
Execute the erroneous command directly to see if the problem persists
|
||||||
-->
|
-->
|
||||||
- [ ] Yes
|
- [ ] Yes
|
||||||
@@ -53,15 +53,15 @@ Execute the erroneous command directly to see if the problem persists
|
|||||||
- [ ] Yes
|
- [ ] Yes
|
||||||
- [ ] No
|
- [ ] No
|
||||||
|
|
||||||
If yes, does the issue still occur when you run topgrade directlly in your
|
If yes, does the issue still occur when you run topgrade directly in your
|
||||||
remote host
|
remote host
|
||||||
|
|
||||||
- [ ] Yes
|
- [ ] Yes
|
||||||
- [ ] No
|
- [ ] No
|
||||||
|
|
||||||
## Configuration file (Optional)
|
## Configuration file (Optional)
|
||||||
<!--
|
<!--
|
||||||
Paste your configuration file inside the code block if you think this issue is
|
Paste your configuration file inside the code block if you think this issue is
|
||||||
related to configuration.
|
related to configuration.
|
||||||
-->
|
-->
|
||||||
|
|
||||||
@@ -74,15 +74,15 @@ related to configuration.
|
|||||||
<!-- For example, Fedora Linux 38 -->
|
<!-- For example, Fedora Linux 38 -->
|
||||||
|
|
||||||
- Installation
|
- Installation
|
||||||
<!--
|
<!--
|
||||||
How did you install topgrade: build from repo / crates.io (cargo install topgrade)
|
How did you install topgrade: build from repo / crates.io (cargo install topgrade)
|
||||||
/ package manager (which one) / other (describe)
|
/ package manager (which one) / other (describe)
|
||||||
-->
|
-->
|
||||||
|
|
||||||
- Topgrade version (`topgrade -V`)
|
- Topgrade version (`topgrade -V`)
|
||||||
|
|
||||||
## Verbose Output (`topgrade -v`)
|
## Verbose Output (`topgrade -v`)
|
||||||
<!--
|
<!--
|
||||||
Paste the verbose output into the pre-tags
|
Paste the verbose output into the pre-tags
|
||||||
-->
|
-->
|
||||||
|
|
||||||
|
|||||||
4
.github/PULL_REQUEST_TEMPLATE.md
vendored
4
.github/PULL_REQUEST_TEMPLATE.md
vendored
@@ -7,12 +7,12 @@
|
|||||||
- [ ] I have read `CONTRIBUTING.md`
|
- [ ] I have read `CONTRIBUTING.md`
|
||||||
- [ ] *Optional:* I have tested the code myself
|
- [ ] *Optional:* I have tested the code myself
|
||||||
- [ ] If this PR introduces new user-facing messages they are translated
|
- [ ] If this PR introduces new user-facing messages they are translated
|
||||||
|
|
||||||
## For new steps
|
## For new steps
|
||||||
|
|
||||||
- [ ] *Optional:* Topgrade skips this step where needed
|
- [ ] *Optional:* Topgrade skips this step where needed
|
||||||
- [ ] *Optional:* The `--dry-run` option works with this step
|
- [ ] *Optional:* The `--dry-run` option works with this step
|
||||||
- [ ] *Optional:* The `--yes` option works with this step if it is supported by
|
- [ ] *Optional:* The `--yes` option works with this step if it is supported by
|
||||||
the underlying command
|
the underlying command
|
||||||
|
|
||||||
If you developed a feature or a bug fix for someone else and you do not have the
|
If you developed a feature or a bug fix for someone else and you do not have the
|
||||||
|
|||||||
18
.github/dependabot.yml
vendored
18
.github/dependabot.yml
vendored
@@ -2,9 +2,23 @@
|
|||||||
|
|
||||||
version: 2
|
version: 2
|
||||||
updates:
|
updates:
|
||||||
|
|
||||||
- package-ecosystem: "github-actions"
|
- package-ecosystem: "github-actions"
|
||||||
directory: "/"
|
directory: "/"
|
||||||
schedule:
|
schedule:
|
||||||
# Check for updates to GitHub Actions every week
|
|
||||||
interval: "weekly"
|
interval: "weekly"
|
||||||
|
|
||||||
|
- package-ecosystem: cargo
|
||||||
|
directory: "/"
|
||||||
|
schedule:
|
||||||
|
interval: "weekly"
|
||||||
|
day: "monday"
|
||||||
|
time: "06:00"
|
||||||
|
timezone: "UTC"
|
||||||
|
versioning-strategy: increase
|
||||||
|
labels: ["dependencies", "cargo"]
|
||||||
|
commit-message:
|
||||||
|
prefix: "deps(cargo)"
|
||||||
|
include: "scope"
|
||||||
|
groups:
|
||||||
|
cargo-minor-patch:
|
||||||
|
update-types: ["minor", "patch"]
|
||||||
|
|||||||
@@ -7,15 +7,18 @@ env:
|
|||||||
CARGO_TERM_COLOR: always
|
CARGO_TERM_COLOR: always
|
||||||
|
|
||||||
|
|
||||||
|
permissions:
|
||||||
|
contents: read
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
TestConfig:
|
TestConfig:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v4
|
- uses: actions/checkout@v5.0.0
|
||||||
- run: |
|
- run: |
|
||||||
CONFIG_PATH=~/.config/topgrade.toml;
|
CONFIG_PATH=~/.config/topgrade.toml;
|
||||||
if [ -f "$CONFIG_PATH" ]; then rm $CONFIG_PATH; fi
|
if [ -f "$CONFIG_PATH" ]; then rm $CONFIG_PATH; fi
|
||||||
cargo build;
|
cargo build;
|
||||||
TOPGRADE_SKIP_BRKC_NOTIFY=true ./target/debug/topgrade --dry-run --only system;
|
TOPGRADE_SKIP_BRKC_NOTIFY=true ./target/debug/topgrade --dry-run --only system;
|
||||||
stat $CONFIG_PATH;
|
stat $CONFIG_PATH;
|
||||||
|
|||||||
5
.github/workflows/check_i18n.yml
vendored
5
.github/workflows/check_i18n.yml
vendored
@@ -6,12 +6,15 @@ on:
|
|||||||
|
|
||||||
name: Check i18n
|
name: Check i18n
|
||||||
|
|
||||||
|
permissions:
|
||||||
|
contents: read
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
check_locale:
|
check_locale:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout code
|
- name: Checkout code
|
||||||
uses: actions/checkout@v4
|
uses: actions/checkout@v5.0.0
|
||||||
|
|
||||||
- name: Install checker
|
- name: Install checker
|
||||||
# Build it with the dev profile as this is faster and the checker still works
|
# Build it with the dev profile as this is faster and the checker still works
|
||||||
|
|||||||
@@ -11,6 +11,9 @@ on:
|
|||||||
branches:
|
branches:
|
||||||
- main
|
- main
|
||||||
|
|
||||||
|
permissions:
|
||||||
|
contents: read
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
lint:
|
lint:
|
||||||
name: DevSkim
|
name: DevSkim
|
||||||
@@ -21,12 +24,12 @@ jobs:
|
|||||||
security-events: write
|
security-events: write
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout code
|
- name: Checkout code
|
||||||
uses: actions/checkout@v4
|
uses: actions/checkout@v5.0.0
|
||||||
|
|
||||||
- name: Run DevSkim scanner
|
- name: Run DevSkim scanner
|
||||||
uses: microsoft/DevSkim-Action@v1
|
uses: microsoft/DevSkim-Action@4b5047945a44163b94642a1cecc0d93a3f428cc6 # v1.0.16
|
||||||
|
|
||||||
- name: Upload DevSkim scan results to GitHub Security tab
|
- name: Upload DevSkim scan results to GitHub Security tab
|
||||||
uses: github/codeql-action/upload-sarif@v3
|
uses: github/codeql-action/upload-sarif@v4.31.0
|
||||||
with:
|
with:
|
||||||
sarif_file: devskim-results.sarif
|
sarif_file: devskim-results.sarif
|
||||||
|
|||||||
27
.github/workflows/check_semver.yml
vendored
27
.github/workflows/check_semver.yml
vendored
@@ -1,27 +0,0 @@
|
|||||||
on:
|
|
||||||
release:
|
|
||||||
types: [published, edited]
|
|
||||||
|
|
||||||
name: Check SemVer compliance
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
prepare:
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@v4
|
|
||||||
- uses: actions-rs/toolchain@v1
|
|
||||||
with:
|
|
||||||
toolchain: nightly-2022-08-03
|
|
||||||
override: true
|
|
||||||
components: rustfmt, clippy
|
|
||||||
|
|
||||||
semver:
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
steps:
|
|
||||||
- uses: actions-rs/cargo@v1
|
|
||||||
with:
|
|
||||||
command: install
|
|
||||||
args: --git https://github.com/rust-lang/rust-semverver
|
|
||||||
- run: eval "current_version=$(grep -e '^version = .*$' Cargo.toml | cut -d ' ' -f 3)"
|
|
||||||
- run: cargo semver | tee semver_out
|
|
||||||
- run: (head -n 1 semver_out | grep "\-> $current_version") || (echo "versioning mismatch" && return 1)
|
|
||||||
76
.github/workflows/ci.yml
vendored
76
.github/workflows/ci.yml
vendored
@@ -10,22 +10,82 @@ env:
|
|||||||
CROSS_VER: '0.2.5'
|
CROSS_VER: '0.2.5'
|
||||||
CARGO_NET_RETRY: 3
|
CARGO_NET_RETRY: 3
|
||||||
|
|
||||||
|
permissions:
|
||||||
|
contents: read
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
fmt:
|
fmt:
|
||||||
name: Rustfmt
|
name: Rustfmt
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout code
|
- name: Checkout code
|
||||||
uses: actions/checkout@v4
|
uses: actions/checkout@v5.0.0
|
||||||
|
|
||||||
- name: Run cargo fmt
|
- name: Run cargo fmt
|
||||||
env:
|
env:
|
||||||
TERM: xterm-256color
|
TERM: xterm-256color
|
||||||
run: |
|
run: |
|
||||||
|
rustup component add rustfmt
|
||||||
cargo fmt --all -- --check
|
cargo fmt --all -- --check
|
||||||
|
|
||||||
|
custom-checks:
|
||||||
|
name: Custom checks
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- name: Checkout code
|
||||||
|
uses: actions/checkout@v5.0.0
|
||||||
|
|
||||||
|
- name: Check if `Step` enum is sorted
|
||||||
|
run: |
|
||||||
|
ENUM_NAME="Step"
|
||||||
|
FILE="src/step.rs"
|
||||||
|
awk "/enum $ENUM_NAME/,/}/" "$FILE" | \
|
||||||
|
grep -E '^\s*[A-Za-z_][A-Za-z0-9_]*\s*,?$' | \
|
||||||
|
sed 's/[, ]//g' > original.txt
|
||||||
|
sort original.txt > sorted.txt
|
||||||
|
diff original.txt sorted.txt
|
||||||
|
|
||||||
|
- name: Check if `Step::run()`'s match is sorted
|
||||||
|
run: |
|
||||||
|
FILE="src/step.rs"
|
||||||
|
awk '/[[:alpha:]] =>/{print $1}' $FILE > original.txt
|
||||||
|
sort original.txt > sorted.txt
|
||||||
|
diff original.txt sorted.txt
|
||||||
|
|
||||||
|
- name: Check if `default_steps` contains every step
|
||||||
|
run: |
|
||||||
|
# Extract all variants from enum Step
|
||||||
|
all_variants=$(sed -n '/^pub enum Step {/,/^}/p' src/step.rs | grep -Po '^\s*\K[A-Z][A-Za-z0-9_]*' | sort)
|
||||||
|
|
||||||
|
# Extract variants used inside default_steps
|
||||||
|
used_variants=$(sed -n '/^pub(crate) fn default_steps()/,/^}/p' src/step.rs | \
|
||||||
|
grep -Po '\b[A-Z][A-Za-z0-9_]*\b' | \
|
||||||
|
grep -Fx -f <(echo "$all_variants") | \
|
||||||
|
sort)
|
||||||
|
|
||||||
|
# Check for missing variants
|
||||||
|
missing=$(comm -23 <(echo "$all_variants") <(echo "$used_variants"))
|
||||||
|
if [[ -z "$missing" ]]; then
|
||||||
|
echo "All variants are used."
|
||||||
|
else
|
||||||
|
echo "Missing variants:"
|
||||||
|
echo "$missing"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Check for duplicates
|
||||||
|
duplicates=$(echo "$used_variants" | uniq -c | awk '$1 > 1 {print $2}')
|
||||||
|
if [[ -z "$duplicates" ]]; then
|
||||||
|
echo "No duplicates found."
|
||||||
|
else
|
||||||
|
echo "Duplicates found:"
|
||||||
|
echo "$duplicates"
|
||||||
|
# We allow duplicates, but lets keep this check for potential future usefulness
|
||||||
|
# exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
main:
|
main:
|
||||||
needs: fmt
|
needs: [ fmt, custom-checks ]
|
||||||
name: ${{ matrix.target_name }} (check, clippy)
|
name: ${{ matrix.target_name }} (check, clippy)
|
||||||
runs-on: ${{ matrix.os }}
|
runs-on: ${{ matrix.os }}
|
||||||
strategy:
|
strategy:
|
||||||
@@ -48,7 +108,7 @@ jobs:
|
|||||||
|
|
||||||
- target: x86_64-apple-darwin
|
- target: x86_64-apple-darwin
|
||||||
target_name: macOS-x86_64
|
target_name: macOS-x86_64
|
||||||
os: macos-13
|
os: macos-15-intel
|
||||||
|
|
||||||
- target: aarch64-apple-darwin
|
- target: aarch64-apple-darwin
|
||||||
target_name: macOS-aarch64
|
target_name: macOS-aarch64
|
||||||
@@ -64,10 +124,10 @@ jobs:
|
|||||||
os: windows-latest
|
os: windows-latest
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout code
|
- name: Checkout code
|
||||||
uses: actions/checkout@v4
|
uses: actions/checkout@v5.0.0
|
||||||
|
|
||||||
- name: Setup Rust Cache
|
- name: Setup Rust Cache
|
||||||
uses: Swatinem/rust-cache@v2
|
uses: Swatinem/rust-cache@f13886b937689c021905a6b90929199931d60db1 # v2.8.1
|
||||||
with:
|
with:
|
||||||
prefix-key: ${{ matrix.target }}
|
prefix-key: ${{ matrix.target }}
|
||||||
|
|
||||||
@@ -79,9 +139,11 @@ jobs:
|
|||||||
run: ${{ matrix.use_cross == true && 'cross' || 'cargo' }} check --locked --target ${{ matrix.target }}
|
run: ${{ matrix.use_cross == true && 'cross' || 'cargo' }} check --locked --target ${{ matrix.target }}
|
||||||
|
|
||||||
- name: Run cargo/cross clippy
|
- name: Run cargo/cross clippy
|
||||||
run: ${{ matrix.use_cross == true && 'cross' || 'cargo' }} clippy --locked --target ${{ matrix.target }} --all-features -- -D warnings
|
run: |
|
||||||
|
rustup component add clippy
|
||||||
|
${{ matrix.use_cross == true && 'cross' || 'cargo' }} clippy --locked --target ${{ matrix.target }} --all-features -- -D warnings
|
||||||
|
|
||||||
- name: Run cargo test
|
- name: Run cargo test
|
||||||
# ONLY run test with cargo
|
# ONLY run test with cargo
|
||||||
if: matrix.use_cross == false
|
if: matrix.use_cross == false
|
||||||
run: cargo test --locked --target ${{ matrix.target }}
|
run: cargo test --locked --target ${{ matrix.target }}
|
||||||
|
|||||||
233
.github/workflows/create_release_assets.yml
vendored
233
.github/workflows/create_release_assets.yml
vendored
@@ -1,26 +1,41 @@
|
|||||||
name: Publish release files for CD native environments
|
name: Publish release files for CD native and non-cd-native environments
|
||||||
|
|
||||||
on:
|
on:
|
||||||
# workflow_run:
|
repository_dispatch:
|
||||||
# workflows: ["Check SemVer compliance"]
|
types: [ release-created ]
|
||||||
# types:
|
|
||||||
# - completed
|
permissions:
|
||||||
release:
|
contents: read
|
||||||
types: [ created ]
|
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
build:
|
# Publish release files for CD native environments
|
||||||
|
native_build:
|
||||||
|
permissions:
|
||||||
|
# Use to sign the release artifacts
|
||||||
|
id-token: write
|
||||||
|
# Used to upload release artifacts
|
||||||
|
contents: write
|
||||||
|
# Used to generate artifact attestations
|
||||||
|
attestations: write
|
||||||
strategy:
|
strategy:
|
||||||
fail-fast: false
|
fail-fast: false
|
||||||
matrix:
|
matrix:
|
||||||
platform: [ ubuntu-latest, macos-latest, macos-13, windows-latest ]
|
# Use the Ubuntu 22.04 image to link with a low version of glibc
|
||||||
|
#
|
||||||
|
# https://github.com/topgrade-rs/topgrade/issues/1095
|
||||||
|
platform: [ ubuntu-22.04, macos-latest, macos-15-intel, windows-latest ]
|
||||||
runs-on: ${{ matrix.platform }}
|
runs-on: ${{ matrix.platform }}
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v4
|
- uses: actions/checkout@v5.0.0
|
||||||
|
|
||||||
|
- name: Install needed components
|
||||||
|
run: |
|
||||||
|
rustup component add rustfmt
|
||||||
|
rustup component add clippy
|
||||||
|
|
||||||
- name: Install cargo-deb
|
- name: Install cargo-deb
|
||||||
run: cargo install cargo-deb
|
run: cargo install cargo-deb
|
||||||
if: ${{ matrix.platform == 'ubuntu-latest' }}
|
if: ${{ startsWith(matrix.platform, 'ubuntu-') }}
|
||||||
shell: bash
|
shell: bash
|
||||||
|
|
||||||
- name: Check format
|
- name: Check format
|
||||||
@@ -35,6 +50,29 @@ jobs:
|
|||||||
- name: Run tests
|
- name: Run tests
|
||||||
run: cargo test
|
run: cargo test
|
||||||
|
|
||||||
|
# Used `https://github.com/BurntSushi/ripgrep/blob/master/.github/workflows/release.yml`
|
||||||
|
# as a reference.
|
||||||
|
- name: Build debug binary to create release assets
|
||||||
|
shell: bash
|
||||||
|
run: |
|
||||||
|
cargo build --all-features
|
||||||
|
bin="target/debug/topgrade"
|
||||||
|
echo "BIN=$bin" >> $GITHUB_ENV
|
||||||
|
|
||||||
|
- name: Create deployment directory
|
||||||
|
shell: bash
|
||||||
|
run: |
|
||||||
|
dir=deployment/deb
|
||||||
|
mkdir -p "$dir"
|
||||||
|
echo "DEPLOY_DIR=$dir" >> $GITHUB_ENV
|
||||||
|
|
||||||
|
- name: Generate shell completions
|
||||||
|
shell: bash
|
||||||
|
run: |
|
||||||
|
"$BIN" --gen-completion bash > "$DEPLOY_DIR/topgrade.bash"
|
||||||
|
"$BIN" --gen-completion fish > "$DEPLOY_DIR/topgrade.fish"
|
||||||
|
"$BIN" --gen-completion zsh > "$DEPLOY_DIR/_topgrade"
|
||||||
|
|
||||||
- name: Build in Release profile with all features enabled
|
- name: Build in Release profile with all features enabled
|
||||||
run: cargo build --release --all-features
|
run: cargo build --release --all-features
|
||||||
|
|
||||||
@@ -42,7 +80,7 @@ jobs:
|
|||||||
run: |
|
run: |
|
||||||
cargo install default-target
|
cargo install default-target
|
||||||
mkdir -p assets
|
mkdir -p assets
|
||||||
FILENAME=topgrade-${{github.event.release.tag_name}}-$(default-target)
|
FILENAME=topgrade-${{ github.event.client_payload.tag }}-$(default-target)
|
||||||
mv target/release/topgrade assets
|
mv target/release/topgrade assets
|
||||||
cd assets
|
cd assets
|
||||||
tar --format=ustar -czf $FILENAME.tar.gz topgrade
|
tar --format=ustar -czf $FILENAME.tar.gz topgrade
|
||||||
@@ -59,21 +97,21 @@ jobs:
|
|||||||
rm -rf target/release
|
rm -rf target/release
|
||||||
cargo build --release
|
cargo build --release
|
||||||
cargo deb --no-build --no-strip
|
cargo deb --no-build --no-strip
|
||||||
if: ${{ matrix.platform == 'ubuntu-latest' }}
|
if: ${{ startsWith(matrix.platform, 'ubuntu-') }}
|
||||||
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/debian/*.deb assets
|
mv target/debian/*.deb assets
|
||||||
if: ${{ matrix.platform == 'ubuntu-latest' }}
|
if: ${{ startsWith(matrix.platform, 'ubuntu-') }}
|
||||||
shell: bash
|
shell: bash
|
||||||
|
|
||||||
- name: Rename Release (Windows)
|
- name: Rename Release (Windows)
|
||||||
run: |
|
run: |
|
||||||
cargo install default-target
|
cargo install default-target
|
||||||
mkdir assets
|
mkdir assets
|
||||||
FILENAME=topgrade-${{github.event.release.tag_name}}-$(default-target)
|
FILENAME=topgrade-${{ github.event.client_payload.tag }}-$(default-target)
|
||||||
mv target/release/topgrade.exe assets/topgrade.exe
|
mv target/release/topgrade.exe assets/topgrade.exe
|
||||||
cd assets
|
cd assets
|
||||||
powershell Compress-Archive -Path * -Destination ${FILENAME}.zip
|
powershell Compress-Archive -Path * -Destination ${FILENAME}.zip
|
||||||
@@ -82,7 +120,166 @@ jobs:
|
|||||||
if: ${{ matrix.platform == 'windows-latest' }}
|
if: ${{ matrix.platform == 'windows-latest' }}
|
||||||
shell: bash
|
shell: bash
|
||||||
|
|
||||||
- name: Release
|
- name: Upload assets
|
||||||
uses: softprops/action-gh-release@v2
|
run:
|
||||||
|
gh release upload "${{ github.event.client_payload.tag }}" assets/*
|
||||||
|
env:
|
||||||
|
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
|
||||||
|
- name: Generate artifact attestations
|
||||||
|
uses: actions/attest-build-provenance@v3.0.0
|
||||||
with:
|
with:
|
||||||
files: assets/*
|
subject-path: assets/*
|
||||||
|
|
||||||
|
# Publish release files for non-CD-native environments
|
||||||
|
cross_build:
|
||||||
|
permissions:
|
||||||
|
# Use to sign the release artifacts
|
||||||
|
id-token: write
|
||||||
|
# Used to upload release artifacts
|
||||||
|
contents: write
|
||||||
|
# Used to generate artifact attestations
|
||||||
|
attestations: write
|
||||||
|
strategy:
|
||||||
|
fail-fast: false
|
||||||
|
matrix:
|
||||||
|
target:
|
||||||
|
[
|
||||||
|
"aarch64-unknown-linux-gnu",
|
||||||
|
"armv7-unknown-linux-gnueabihf",
|
||||||
|
"x86_64-unknown-linux-musl",
|
||||||
|
"aarch64-unknown-linux-musl",
|
||||||
|
"x86_64-unknown-freebsd",
|
||||||
|
]
|
||||||
|
# Run this one on an older version as well, to limit glibc to 2.34 instead of 2.39.
|
||||||
|
# Even though this is cross-compiled, it links to the libc6-<arch>-cross installed on the host
|
||||||
|
# (see the apt-get install calls below)
|
||||||
|
runs-on: ubuntu-22.04
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v5.0.0
|
||||||
|
|
||||||
|
- name: Install needed components
|
||||||
|
run: |
|
||||||
|
rustup component add rustfmt
|
||||||
|
rustup component add clippy
|
||||||
|
|
||||||
|
- name: Install cargo-deb cross compilation dependencies
|
||||||
|
run: sudo apt-get install libc6-arm64-cross libgcc-s1-arm64-cross
|
||||||
|
if: ${{ matrix.target == 'aarch64-unknown-linux-gnu' }}
|
||||||
|
shell: bash
|
||||||
|
|
||||||
|
- name: Install cargo-deb cross compilation dependencies for armv7
|
||||||
|
run: sudo apt-get install libc6-armhf-cross libgcc-s1-armhf-cross
|
||||||
|
if: ${{ matrix.target == 'armv7-unknown-linux-gnueabihf' }}
|
||||||
|
shell: bash
|
||||||
|
|
||||||
|
- name: Install cargo-deb
|
||||||
|
run: cargo install cargo-deb
|
||||||
|
if: ${{ matrix.target == 'aarch64-unknown-linux-gnu' || matrix.target == 'armv7-unknown-linux-gnueabihf' }}
|
||||||
|
shell: bash
|
||||||
|
|
||||||
|
- name: install targets
|
||||||
|
run: rustup target add ${{ matrix.target }}
|
||||||
|
|
||||||
|
- name: install cross
|
||||||
|
# Install from source to fix `ld: cannot find -lgeom` for freebsd build
|
||||||
|
run: cargo +stable install --git https://github.com/cross-rs/cross cross
|
||||||
|
|
||||||
|
- name: Run clippy
|
||||||
|
run: cross clippy --all-targets --locked --target ${{matrix.target}} -- -D warnings
|
||||||
|
|
||||||
|
- name: Run clippy (All features)
|
||||||
|
run: cross clippy --locked --all-features --target ${{matrix.target}} -- -D warnings
|
||||||
|
|
||||||
|
- name: Run tests
|
||||||
|
run: cross test --target ${{matrix.target}}
|
||||||
|
# Running tests on FreeBSD is impossible; see https://github.com/cross-rs/cross/wiki/FAQ#running-bsd-tests
|
||||||
|
# Not that this is *NOT* the same as the original issue with `ld: cannot find -lgeom`, but a new issue:
|
||||||
|
# error: test failed, to rerun pass `--lib`
|
||||||
|
# Caused by:
|
||||||
|
# could not execute process `/target/x86_64-unknown-freebsd/debug/deps/topgrade-9b1670d87ca863dd` (never executed)
|
||||||
|
# Caused by:
|
||||||
|
# No such file or directory (os error 2)
|
||||||
|
# TODO: I have not tested this in GHA yet, only locally
|
||||||
|
if: ${{ matrix.target != 'x86_64-unknown-freebsd' }}
|
||||||
|
|
||||||
|
# Used `https://github.com/BurntSushi/ripgrep/blob/master/.github/workflows/release.yml`
|
||||||
|
# as a reference.
|
||||||
|
- name: Build debug binary to create release assets
|
||||||
|
shell: bash
|
||||||
|
run: |
|
||||||
|
# This build is not using the target arch since this binary is only needed in CI. It needs
|
||||||
|
# to be the compiled for the runner since it has the run the binary to generate completion
|
||||||
|
# scripts.
|
||||||
|
cargo build --all-features
|
||||||
|
bin="target/debug/topgrade"
|
||||||
|
echo "BIN=$bin" >> $GITHUB_ENV
|
||||||
|
|
||||||
|
- name: Create deployment directory
|
||||||
|
shell: bash
|
||||||
|
run: |
|
||||||
|
dir=deployment/deb
|
||||||
|
mkdir -p "$dir"
|
||||||
|
echo "DEPLOY_DIR=$dir" >> $GITHUB_ENV
|
||||||
|
|
||||||
|
- name: Generate shell completions
|
||||||
|
shell: bash
|
||||||
|
run: |
|
||||||
|
"$BIN" --gen-completion bash > "$DEPLOY_DIR/topgrade.bash"
|
||||||
|
"$BIN" --gen-completion fish > "$DEPLOY_DIR/topgrade.fish"
|
||||||
|
"$BIN" --gen-completion zsh > "$DEPLOY_DIR/_topgrade"
|
||||||
|
|
||||||
|
- name: Build in Release profile with all features enabled
|
||||||
|
run: cross build --release --all-features --target ${{matrix.target}}
|
||||||
|
|
||||||
|
- name: Rename Release
|
||||||
|
run: |
|
||||||
|
mkdir -p assets
|
||||||
|
FILENAME=topgrade-${{ github.event.client_payload.tag }}-${{matrix.target}}
|
||||||
|
mv target/${{matrix.target}}/release/topgrade assets
|
||||||
|
cd assets
|
||||||
|
tar --format=ustar -czf $FILENAME.tar.gz topgrade
|
||||||
|
rm topgrade
|
||||||
|
ls .
|
||||||
|
|
||||||
|
- name: Build Debian-based system package without autoupdate feature
|
||||||
|
# First remove the binary built by previous steps
|
||||||
|
# because we don't want the auto-update feature,
|
||||||
|
# then build the new binary without auto-updating.
|
||||||
|
run: |
|
||||||
|
rm -rf target/${{matrix.target}}
|
||||||
|
cross build --release --target ${{matrix.target}}
|
||||||
|
cargo deb --target=${{matrix.target}} --no-build --no-strip
|
||||||
|
if: ${{ matrix.target == 'aarch64-unknown-linux-gnu' || matrix.target == 'armv7-unknown-linux-gnueabihf' }}
|
||||||
|
shell: bash
|
||||||
|
|
||||||
|
- name: Move Debian-based system package
|
||||||
|
run: |
|
||||||
|
mkdir -p assets
|
||||||
|
mv target/${{matrix.target}}/debian/*.deb assets
|
||||||
|
if: ${{ matrix.target == 'aarch64-unknown-linux-gnu' || matrix.target == 'armv7-unknown-linux-gnueabihf' }}
|
||||||
|
shell: bash
|
||||||
|
|
||||||
|
|
||||||
|
- name: Upload assets
|
||||||
|
run:
|
||||||
|
gh release upload "${{ github.event.client_payload.tag }}" assets/*
|
||||||
|
env:
|
||||||
|
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
|
||||||
|
- name: Generate artifact attestations
|
||||||
|
uses: actions/attest-build-provenance@v3.0.0
|
||||||
|
with:
|
||||||
|
subject-path: assets/*
|
||||||
|
|
||||||
|
triggers:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
needs: [ native_build, cross_build ]
|
||||||
|
steps:
|
||||||
|
- name: Trigger workflows
|
||||||
|
run: |
|
||||||
|
gh api repos/${{ github.repository }}/dispatches \
|
||||||
|
-f "event_type=release-assets-built" \
|
||||||
|
-F "client_payload[tag]=${{ github.event.client_payload.tag }}"
|
||||||
|
env:
|
||||||
|
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
|||||||
@@ -1,97 +0,0 @@
|
|||||||
name: Publish release files for non-cd-native environments
|
|
||||||
|
|
||||||
on:
|
|
||||||
# workflow_run:
|
|
||||||
# workflows: ["Check SemVer compliance"]
|
|
||||||
# types:
|
|
||||||
# - completed
|
|
||||||
release:
|
|
||||||
types: [created]
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
build:
|
|
||||||
strategy:
|
|
||||||
fail-fast: false
|
|
||||||
matrix:
|
|
||||||
target:
|
|
||||||
[
|
|
||||||
"aarch64-unknown-linux-gnu",
|
|
||||||
"armv7-unknown-linux-gnueabihf",
|
|
||||||
"x86_64-unknown-linux-musl",
|
|
||||||
"aarch64-unknown-linux-musl",
|
|
||||||
"x86_64-unknown-freebsd",
|
|
||||||
]
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@v4
|
|
||||||
|
|
||||||
- name: Install cargo-deb cross compilation dependencies
|
|
||||||
run: sudo apt-get install libc6-arm64-cross libgcc-s1-arm64-cross
|
|
||||||
if: ${{ matrix.target == 'aarch64-unknown-linux-gnu' }}
|
|
||||||
shell: bash
|
|
||||||
|
|
||||||
- name: Install cargo-deb cross compilation dependencies for armv7
|
|
||||||
run: sudo apt-get install libc6-armhf-cross libgcc-s1-armhf-cross
|
|
||||||
if: ${{ matrix.target == 'armv7-unknown-linux-gnueabihf' }}
|
|
||||||
shell: bash
|
|
||||||
|
|
||||||
- name: Install cargo-deb
|
|
||||||
run: cargo install cargo-deb
|
|
||||||
if: ${{ matrix.target == 'aarch64-unknown-linux-gnu' || matrix.target == 'armv7-unknown-linux-gnueabihf' }}
|
|
||||||
shell: bash
|
|
||||||
|
|
||||||
- name: install targets
|
|
||||||
run: rustup target add ${{ matrix.target }}
|
|
||||||
|
|
||||||
- name: install cross
|
|
||||||
uses: taiki-e/install-action@v2
|
|
||||||
with:
|
|
||||||
tool: cross@0.2.5
|
|
||||||
|
|
||||||
- name: Check format
|
|
||||||
run: cross fmt --all -- --check
|
|
||||||
|
|
||||||
- name: Run clippy
|
|
||||||
run: cross clippy --all-targets --locked --target ${{matrix.target}} -- -D warnings
|
|
||||||
|
|
||||||
- name: Run clippy (All features)
|
|
||||||
run: cross clippy --locked --all-features --target ${{matrix.target}} -- -D warnings
|
|
||||||
|
|
||||||
- name: Run tests
|
|
||||||
run: cross test --target ${{matrix.target}}
|
|
||||||
|
|
||||||
- name: Build in Release profile with all features enabled
|
|
||||||
run: cross build --release --all-features --target ${{matrix.target}}
|
|
||||||
|
|
||||||
- name: Rename Release
|
|
||||||
run: |
|
|
||||||
mkdir -p assets
|
|
||||||
FILENAME=topgrade-${{github.event.release.tag_name}}-${{matrix.target}}
|
|
||||||
mv target/${{matrix.target}}/release/topgrade assets
|
|
||||||
cd assets
|
|
||||||
tar --format=ustar -czf $FILENAME.tar.gz topgrade
|
|
||||||
rm topgrade
|
|
||||||
ls .
|
|
||||||
|
|
||||||
- name: Build Debian-based system package without autoupdate feature
|
|
||||||
# First remove the binary built by previous steps
|
|
||||||
# because we don't want the auto-update feature,
|
|
||||||
# then build the new binary without auto-updating.
|
|
||||||
run: |
|
|
||||||
rm -rf target/${{matrix.target}}
|
|
||||||
cross build --release --target ${{matrix.target}}
|
|
||||||
cargo deb --target=${{matrix.target}} --no-build --no-strip
|
|
||||||
if: ${{ matrix.target == 'aarch64-unknown-linux-gnu' || matrix.target == 'armv7-unknown-linux-gnueabihf' }}
|
|
||||||
shell: bash
|
|
||||||
|
|
||||||
- name: Move Debian-based system package
|
|
||||||
run: |
|
|
||||||
mkdir -p assets
|
|
||||||
mv target/${{matrix.target}}/debian/*.deb assets
|
|
||||||
if: ${{ matrix.target == 'aarch64-unknown-linux-gnu' || matrix.target == 'armv7-unknown-linux-gnueabihf' }}
|
|
||||||
shell: bash
|
|
||||||
|
|
||||||
- name: Release
|
|
||||||
uses: softprops/action-gh-release@v2
|
|
||||||
with:
|
|
||||||
files: assets/*
|
|
||||||
22
.github/workflows/dependency-review.yml
vendored
Normal file
22
.github/workflows/dependency-review.yml
vendored
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
# Dependency Review Action
|
||||||
|
#
|
||||||
|
# This Action will scan dependency manifest files that change as part of a Pull Request,
|
||||||
|
# surfacing known-vulnerable versions of the packages declared or updated in the PR.
|
||||||
|
# Once installed, if the workflow run is marked as required,
|
||||||
|
# PRs introducing known-vulnerable packages will be blocked from merging.
|
||||||
|
#
|
||||||
|
# Source repository: https://github.com/actions/dependency-review-action
|
||||||
|
name: 'Dependency Review'
|
||||||
|
on: [pull_request]
|
||||||
|
|
||||||
|
permissions:
|
||||||
|
contents: read
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
dependency-review:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- name: 'Checkout Repository'
|
||||||
|
uses: actions/checkout@v5.0.0
|
||||||
|
- name: 'Dependency Review'
|
||||||
|
uses: actions/dependency-review-action@40c09b7dc99638e5ddb0bfd91c1673effc064d8a # v4.8.1
|
||||||
63
.github/workflows/release-plz.yml
vendored
Normal file
63
.github/workflows/release-plz.yml
vendored
Normal file
@@ -0,0 +1,63 @@
|
|||||||
|
name: Release-plz
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches:
|
||||||
|
- main
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
|
||||||
|
# Release unpublished packages.
|
||||||
|
release-plz-release:
|
||||||
|
name: Release-plz release
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
environment: crates_io
|
||||||
|
permissions:
|
||||||
|
contents: write
|
||||||
|
id-token: write # For trusted publishing
|
||||||
|
steps:
|
||||||
|
- &checkout
|
||||||
|
name: Checkout repository
|
||||||
|
uses: actions/checkout@v5
|
||||||
|
with:
|
||||||
|
fetch-depth: 0
|
||||||
|
persist-credentials: false
|
||||||
|
- &install-rust
|
||||||
|
name: Install Rust toolchain
|
||||||
|
uses: dtolnay/rust-toolchain@stable
|
||||||
|
- name: Run release-plz
|
||||||
|
id: release-plz
|
||||||
|
uses: release-plz/action@v0.5
|
||||||
|
with:
|
||||||
|
command: release
|
||||||
|
env:
|
||||||
|
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
|
||||||
|
- name: Trigger workflows
|
||||||
|
if: steps.release-plz.outputs.releases_created == 'true'
|
||||||
|
run: |
|
||||||
|
gh api repos/${{ github.repository }}/dispatches \
|
||||||
|
-f "event_type=release-created" \
|
||||||
|
-F "client_payload[tag]=${{ fromJSON(steps.release-plz.outputs.releases)[0].tag }}"
|
||||||
|
env:
|
||||||
|
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
|
||||||
|
# Create a PR with the new versions and changelog, preparing the next release.
|
||||||
|
release-plz-pr:
|
||||||
|
name: Release-plz PR
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
permissions:
|
||||||
|
contents: write
|
||||||
|
pull-requests: write
|
||||||
|
concurrency:
|
||||||
|
group: release-plz-${{ github.ref }}
|
||||||
|
cancel-in-progress: false
|
||||||
|
steps:
|
||||||
|
- *checkout
|
||||||
|
- *install-rust
|
||||||
|
- name: Run release-plz
|
||||||
|
uses: release-plz/action@v0.5
|
||||||
|
with:
|
||||||
|
command: release-pr
|
||||||
|
env:
|
||||||
|
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||||
28
.github/workflows/release_to_aur.yml
vendored
28
.github/workflows/release_to_aur.yml
vendored
@@ -1,30 +1,36 @@
|
|||||||
name: Publish to AUR
|
name: Publish to AUR
|
||||||
|
|
||||||
on:
|
on:
|
||||||
# workflow_run:
|
repository_dispatch:
|
||||||
# workflows: ["Check SemVer compliance"]
|
types: [ release-assets-built ]
|
||||||
# types:
|
|
||||||
# - completed
|
permissions:
|
||||||
push:
|
contents: read
|
||||||
tags:
|
|
||||||
- "v*"
|
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
aur-publish:
|
aur-publish:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
|
- name: Determine version
|
||||||
|
id: determine_version
|
||||||
|
run: |
|
||||||
|
# tag should be something like "v16.0.4", remove the prefix v here
|
||||||
|
tag="${{ github.event.client_payload.tag }}"
|
||||||
|
echo "version=${tag#v}" >> $GITHUB_OUTPUT
|
||||||
|
|
||||||
- name: Publish source AUR package
|
- name: Publish source AUR package
|
||||||
uses: aksh1618/update-aur-package@v1.0.5
|
uses: varabyte/update-aur-package@572e31b1972fa289a27b1926c06a489eb89c7fd7
|
||||||
with:
|
with:
|
||||||
tag_version_prefix: v
|
version: ${{ steps.determine_version.outputs.version }}
|
||||||
package_name: topgrade
|
package_name: topgrade
|
||||||
commit_username: "Thomas Schönauer"
|
commit_username: "Thomas Schönauer"
|
||||||
commit_email: t.schoenauer@hgs-wt.at
|
commit_email: t.schoenauer@hgs-wt.at
|
||||||
ssh_private_key: ${{ secrets.AUR_SSH_PRIVATE_KEY }}
|
ssh_private_key: ${{ secrets.AUR_SSH_PRIVATE_KEY }}
|
||||||
|
|
||||||
- name: Publish binary AUR package
|
- name: Publish binary AUR package
|
||||||
uses: aksh1618/update-aur-package@v1.0.5
|
uses: varabyte/update-aur-package@572e31b1972fa289a27b1926c06a489eb89c7fd7
|
||||||
with:
|
with:
|
||||||
tag_version_prefix: v
|
version: ${{ steps.determine_version.outputs.version }}
|
||||||
package_name: topgrade-bin
|
package_name: topgrade-bin
|
||||||
commit_username: "Thomas Schönauer"
|
commit_username: "Thomas Schönauer"
|
||||||
commit_email: t.schoenauer@hgs-wt.at
|
commit_email: t.schoenauer@hgs-wt.at
|
||||||
|
|||||||
29
.github/workflows/release_to_crates_io.yml
vendored
29
.github/workflows/release_to_crates_io.yml
vendored
@@ -1,29 +0,0 @@
|
|||||||
on:
|
|
||||||
# workflow_run:
|
|
||||||
# workflows: ["Check SemVer compliance"]
|
|
||||||
# types:
|
|
||||||
# - completed
|
|
||||||
release:
|
|
||||||
types: [published]
|
|
||||||
|
|
||||||
name: Publish to crates.io on release
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
prepare:
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@v4
|
|
||||||
- uses: actions-rs/toolchain@v1
|
|
||||||
with:
|
|
||||||
toolchain: stable
|
|
||||||
override: true
|
|
||||||
|
|
||||||
publish:
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
steps:
|
|
||||||
- uses: katyo/publish-crates@v2
|
|
||||||
with:
|
|
||||||
dry-run: true
|
|
||||||
check-repo: ${{ github.event_name == 'push' }}
|
|
||||||
registry-token: ${{ secrets.CARGO_REGISTRY_TOKEN }}
|
|
||||||
ignore-unpublished-changes: true
|
|
||||||
21
.github/workflows/release_to_homebrew.yml
vendored
21
.github/workflows/release_to_homebrew.yml
vendored
@@ -1,14 +1,11 @@
|
|||||||
name: Publish to Homebrew
|
name: Publish to Homebrew
|
||||||
|
|
||||||
on:
|
on:
|
||||||
# workflow_run:
|
repository_dispatch:
|
||||||
# workflows: ["Check SemVer compliance"]
|
types: [ release-created ]
|
||||||
# types:
|
|
||||||
# - completed
|
permissions:
|
||||||
workflow_dispatch:
|
contents: read
|
||||||
push:
|
|
||||||
tags:
|
|
||||||
- "v*"
|
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
homebrew-publish:
|
homebrew-publish:
|
||||||
@@ -16,10 +13,11 @@ jobs:
|
|||||||
steps:
|
steps:
|
||||||
- name: Set up Homebrew
|
- name: Set up Homebrew
|
||||||
id: set-up-homebrew
|
id: set-up-homebrew
|
||||||
uses: Homebrew/actions/setup-homebrew@master
|
uses: Homebrew/actions/setup-homebrew@24a0b15df658487e137fcd20fba32757d41a9411 # master
|
||||||
|
|
||||||
- name: Cache Homebrew Bundler RubyGems
|
- name: Cache Homebrew Bundler RubyGems
|
||||||
id: cache
|
id: cache
|
||||||
uses: actions/cache@v4
|
uses: actions/cache@v4.3.0
|
||||||
with:
|
with:
|
||||||
path: ${{ steps.set-up-homebrew.outputs.gems-path }}
|
path: ${{ steps.set-up-homebrew.outputs.gems-path }}
|
||||||
key: ${{ runner.os }}-rubygems-${{ steps.set-up-homebrew.outputs.gems-hash }}
|
key: ${{ runner.os }}-rubygems-${{ steps.set-up-homebrew.outputs.gems-hash }}
|
||||||
@@ -28,8 +26,9 @@ jobs:
|
|||||||
- name: Install Homebrew Bundler RubyGems
|
- name: Install Homebrew Bundler RubyGems
|
||||||
if: steps.cache.outputs.cache-hit != 'true'
|
if: steps.cache.outputs.cache-hit != 'true'
|
||||||
run: brew install-bundler-gems
|
run: brew install-bundler-gems
|
||||||
|
|
||||||
- name: Bump formulae
|
- name: Bump formulae
|
||||||
uses: Homebrew/actions/bump-packages@master
|
uses: Homebrew/actions/bump-packages@24a0b15df658487e137fcd20fba32757d41a9411 # master
|
||||||
continue-on-error: true
|
continue-on-error: true
|
||||||
with:
|
with:
|
||||||
# Custom GitHub access token with only the 'public_repo' scope enabled
|
# Custom GitHub access token with only the 'public_repo' scope enabled
|
||||||
|
|||||||
60
.github/workflows/release_to_pypi.yml
vendored
60
.github/workflows/release_to_pypi.yml
vendored
@@ -1,31 +1,31 @@
|
|||||||
name: Update PyPi
|
name: Update PyPi
|
||||||
|
|
||||||
on:
|
on:
|
||||||
release:
|
repository_dispatch:
|
||||||
types: [published]
|
types: [ release-created ]
|
||||||
|
|
||||||
permissions:
|
permissions:
|
||||||
contents: read
|
contents: read
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
|
# TODO: make linux/windows/macos/sdist a matrix. See how other workflows do it.
|
||||||
linux:
|
linux:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
strategy:
|
strategy:
|
||||||
matrix:
|
matrix:
|
||||||
target: [x86_64, x86, aarch64]
|
target: [x86_64, x86, aarch64]
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v4
|
- uses: actions/checkout@v5.0.0
|
||||||
- name: Build wheels
|
- name: Build wheels
|
||||||
uses: PyO3/maturin-action@v1
|
uses: PyO3/maturin-action@86b9d133d34bc1b40018696f782949dac11bd380 # v1.49.4
|
||||||
with:
|
with:
|
||||||
target: ${{ matrix.target }}
|
target: ${{ matrix.target }}
|
||||||
args: --release --out dist
|
args: --release --out dist
|
||||||
sccache: 'true'
|
|
||||||
manylinux: auto
|
manylinux: auto
|
||||||
- name: Upload wheels
|
- name: Upload wheels
|
||||||
uses: actions/upload-artifact@v3
|
uses: actions/upload-artifact@v5.0.0
|
||||||
with:
|
with:
|
||||||
name: wheels
|
name: wheels-linux-${{ matrix.target }}
|
||||||
path: dist
|
path: dist
|
||||||
|
|
||||||
windows:
|
windows:
|
||||||
@@ -34,17 +34,16 @@ jobs:
|
|||||||
matrix:
|
matrix:
|
||||||
target: [x64, x86]
|
target: [x64, x86]
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v4
|
- uses: actions/checkout@v5.0.0
|
||||||
- name: Build wheels
|
- name: Build wheels
|
||||||
uses: PyO3/maturin-action@v1
|
uses: PyO3/maturin-action@86b9d133d34bc1b40018696f782949dac11bd380 # v1.49.4
|
||||||
with:
|
with:
|
||||||
target: ${{ matrix.target }}
|
target: ${{ matrix.target }}
|
||||||
args: --release --out dist
|
args: --release --out dist
|
||||||
sccache: 'true'
|
|
||||||
- name: Upload wheels
|
- name: Upload wheels
|
||||||
uses: actions/upload-artifact@v3
|
uses: actions/upload-artifact@v5.0.0
|
||||||
with:
|
with:
|
||||||
name: wheels
|
name: wheels-windows-${{ matrix.target }}
|
||||||
path: dist
|
path: dist
|
||||||
|
|
||||||
macos:
|
macos:
|
||||||
@@ -53,47 +52,56 @@ jobs:
|
|||||||
matrix:
|
matrix:
|
||||||
target: [x86_64, aarch64]
|
target: [x86_64, aarch64]
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v4
|
- uses: actions/checkout@v5.0.0
|
||||||
- name: Build wheels
|
- name: Build wheels
|
||||||
uses: PyO3/maturin-action@v1
|
uses: PyO3/maturin-action@86b9d133d34bc1b40018696f782949dac11bd380 # v1.49.4
|
||||||
with:
|
with:
|
||||||
target: ${{ matrix.target }}
|
target: ${{ matrix.target }}
|
||||||
args: --release --out dist
|
args: --release --out dist
|
||||||
sccache: 'true'
|
|
||||||
- name: Upload wheels
|
- name: Upload wheels
|
||||||
uses: actions/upload-artifact@v3
|
uses: actions/upload-artifact@v5.0.0
|
||||||
with:
|
with:
|
||||||
name: wheels
|
name: wheels-macos-${{ matrix.target }}
|
||||||
path: dist
|
path: dist
|
||||||
|
|
||||||
sdist:
|
sdist:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v4
|
- uses: actions/checkout@v5.0.0
|
||||||
- name: Build sdist
|
- name: Build sdist
|
||||||
uses: PyO3/maturin-action@v1
|
uses: PyO3/maturin-action@86b9d133d34bc1b40018696f782949dac11bd380 # v1.49.4
|
||||||
with:
|
with:
|
||||||
command: sdist
|
command: sdist
|
||||||
args: --out dist
|
args: --out dist
|
||||||
- name: Upload sdist
|
- name: Upload sdist
|
||||||
uses: actions/upload-artifact@v3
|
uses: actions/upload-artifact@v5.0.0
|
||||||
with:
|
with:
|
||||||
name: wheels
|
name: wheels-sdist
|
||||||
path: dist
|
path: dist
|
||||||
|
|
||||||
release:
|
release:
|
||||||
name: Release
|
name: Release
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
if: "startsWith(github.ref, 'refs/tags/')"
|
|
||||||
needs: [linux, windows, macos, sdist]
|
needs: [linux, windows, macos, sdist]
|
||||||
|
permissions:
|
||||||
|
# Use to sign the release artifacts
|
||||||
|
id-token: write
|
||||||
|
# Used to upload release artifacts
|
||||||
|
contents: write
|
||||||
|
# Used to generate artifact attestation
|
||||||
|
attestations: write
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/download-artifact@v3
|
- uses: actions/download-artifact@v6.0.0
|
||||||
|
|
||||||
|
- name: Generate artifact attestation
|
||||||
|
uses: actions/attest-build-provenance@v3.0.0
|
||||||
with:
|
with:
|
||||||
name: wheels
|
subject-path: 'wheels-*/*'
|
||||||
|
|
||||||
- name: Publish to PyPI
|
- name: Publish to PyPI
|
||||||
uses: PyO3/maturin-action@v1
|
uses: PyO3/maturin-action@86b9d133d34bc1b40018696f782949dac11bd380 # v1.49.4
|
||||||
env:
|
env:
|
||||||
MATURIN_PYPI_TOKEN: ${{ secrets.PYPI_API_TOKEN }}
|
MATURIN_PYPI_TOKEN: ${{ secrets.PYPI_API_TOKEN }}
|
||||||
with:
|
with:
|
||||||
command: upload
|
command: upload
|
||||||
args: --skip-existing *
|
args: --non-interactive --skip-existing wheels-*/*
|
||||||
|
|||||||
14
.github/workflows/release_to_winget.yml
vendored
14
.github/workflows/release_to_winget.yml
vendored
@@ -1,13 +1,19 @@
|
|||||||
name: Publish to WinGet
|
name: Publish to WinGet
|
||||||
|
|
||||||
on:
|
on:
|
||||||
release:
|
repository_dispatch:
|
||||||
types: [released]
|
types: [ release-created ]
|
||||||
|
|
||||||
|
permissions:
|
||||||
|
contents: read
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
publish:
|
publish:
|
||||||
runs-on: windows-latest
|
runs-on: windows-latest
|
||||||
steps:
|
steps:
|
||||||
- uses: vedantmgoyal2009/winget-releaser@main
|
- uses: vedantmgoyal2009/winget-releaser@19e706d4c9121098010096f9c495a70a7518b30f # main
|
||||||
with:
|
with:
|
||||||
|
release-tag: ${{ github.event.client_payload.tag }}
|
||||||
identifier: topgrade-rs.topgrade
|
identifier: topgrade-rs.topgrade
|
||||||
max-versions-to-keep: 5 # keep only latest 5 versions
|
max-versions-to-keep: 5 # keep only latest 5 versions
|
||||||
token: ${{ secrets.WINGET_TOKEN }}
|
token: ${{ secrets.WINGET_TOKEN }}
|
||||||
|
|||||||
76
.github/workflows/scorecards.yml
vendored
Normal file
76
.github/workflows/scorecards.yml
vendored
Normal file
@@ -0,0 +1,76 @@
|
|||||||
|
# This workflow uses actions that are not certified by GitHub. They are provided
|
||||||
|
# by a third-party and are governed by separate terms of service, privacy
|
||||||
|
# policy, and support documentation.
|
||||||
|
|
||||||
|
name: Scorecard supply-chain security
|
||||||
|
on:
|
||||||
|
# For Branch-Protection check. Only the default branch is supported. See
|
||||||
|
# https://github.com/ossf/scorecard/blob/main/docs/checks.md#branch-protection
|
||||||
|
branch_protection_rule:
|
||||||
|
# To guarantee Maintained check is occasionally updated. See
|
||||||
|
# https://github.com/ossf/scorecard/blob/main/docs/checks.md#maintained
|
||||||
|
schedule:
|
||||||
|
- cron: '20 7 * * 2'
|
||||||
|
push:
|
||||||
|
branches: ["main"]
|
||||||
|
|
||||||
|
# Declare default permissions as read only.
|
||||||
|
permissions: read-all
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
analysis:
|
||||||
|
name: Scorecard analysis
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
permissions:
|
||||||
|
# Needed to upload the results to code-scanning dashboard.
|
||||||
|
security-events: write
|
||||||
|
# Needed to publish results and get a badge (see publish_results below).
|
||||||
|
id-token: write
|
||||||
|
contents: read
|
||||||
|
actions: read
|
||||||
|
# To allow GraphQL ListCommits to work
|
||||||
|
issues: read
|
||||||
|
pull-requests: read
|
||||||
|
# To detect SAST tools
|
||||||
|
checks: read
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- name: "Checkout code"
|
||||||
|
uses: actions/checkout@v5.0.0
|
||||||
|
with:
|
||||||
|
persist-credentials: false
|
||||||
|
|
||||||
|
- name: "Run analysis"
|
||||||
|
uses: ossf/scorecard-action@4eaacf0543bb3f2c246792bd56e8cdeffafb205a # v2.4.3
|
||||||
|
with:
|
||||||
|
results_file: results.sarif
|
||||||
|
results_format: sarif
|
||||||
|
# (Optional) "write" PAT token. Uncomment the `repo_token` line below if:
|
||||||
|
# - you want to enable the Branch-Protection check on a *public* repository, or
|
||||||
|
# - you are installing Scorecards on a *private* repository
|
||||||
|
# To create the PAT, follow the steps in https://github.com/ossf/scorecard-action#authentication-with-pat.
|
||||||
|
# repo_token: ${{ secrets.SCORECARD_TOKEN }}
|
||||||
|
|
||||||
|
# Public repositories:
|
||||||
|
# - Publish results to OpenSSF REST API for easy access by consumers
|
||||||
|
# - Allows the repository to include the Scorecard badge.
|
||||||
|
# - See https://github.com/ossf/scorecard-action#publishing-results.
|
||||||
|
# For private repositories:
|
||||||
|
# - `publish_results` will always be set to `false`, regardless
|
||||||
|
# of the value entered here.
|
||||||
|
publish_results: true
|
||||||
|
|
||||||
|
# Upload the results as artifacts (optional). Commenting out will disable uploads of run results in SARIF
|
||||||
|
# format to the repository Actions tab.
|
||||||
|
- name: "Upload artifact"
|
||||||
|
uses: actions/upload-artifact@v5.0.0
|
||||||
|
with:
|
||||||
|
name: SARIF file
|
||||||
|
path: results.sarif
|
||||||
|
retention-days: 5
|
||||||
|
|
||||||
|
# Upload the results to GitHub's code scanning dashboard.
|
||||||
|
- name: "Upload to code-scanning"
|
||||||
|
uses: github/codeql-action/upload-sarif@v4.31.0
|
||||||
|
with:
|
||||||
|
sarif_file: results.sarif
|
||||||
25
.pre-commit-config.yaml
Normal file
25
.pre-commit-config.yaml
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
repos:
|
||||||
|
- repo: https://github.com/gitleaks/gitleaks
|
||||||
|
rev: v8.28.0
|
||||||
|
hooks:
|
||||||
|
- id: gitleaks
|
||||||
|
|
||||||
|
- repo: https://github.com/shellcheck-py/shellcheck-py
|
||||||
|
rev: v0.11.0.1
|
||||||
|
hooks:
|
||||||
|
- id: shellcheck
|
||||||
|
|
||||||
|
- repo: https://github.com/pre-commit/pre-commit-hooks
|
||||||
|
rev: v6.0.0
|
||||||
|
hooks:
|
||||||
|
- id: end-of-file-fixer
|
||||||
|
- id: trailing-whitespace
|
||||||
|
|
||||||
|
- repo: https://github.com/crate-ci/typos
|
||||||
|
rev: v1.38.1
|
||||||
|
hooks:
|
||||||
|
- id: typos
|
||||||
|
|
||||||
|
|
||||||
|
ci:
|
||||||
|
autoupdate_commit_msg: "chore(pre-commit): autoupdate"
|
||||||
20
.typos.toml
Normal file
20
.typos.toml
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
# Typos configuration (minimal, conservative)
|
||||||
|
# Exclude locales and OS fingerprint data to avoid false positives
|
||||||
|
# - Recognize a few project-specific proper nouns
|
||||||
|
|
||||||
|
[files]
|
||||||
|
extend-exclude = [
|
||||||
|
"src/steps/os/os_release/**",
|
||||||
|
"locales/**",
|
||||||
|
# Include only English locale files - TODO: Split locales/app.yml into a Separate english File
|
||||||
|
# "!locales/en/**"
|
||||||
|
]
|
||||||
|
|
||||||
|
[default]
|
||||||
|
# Mark specific words as always valid by mapping them to themselves
|
||||||
|
check-file = true
|
||||||
|
check-filename = true
|
||||||
|
|
||||||
|
[default.extend-words]
|
||||||
|
# Add project-specific terms that should not be flagged as typos
|
||||||
|
# Example: topgrade = "topgrade"
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
1. The `jet_brains_toolbox` step was renamed to `jetbrains_toolbox`. If you're
|
||||||
|
using the old name in your configuration file in the `disable` or `only`
|
||||||
|
fields, simply change it to `jetbrains_toolbox`.
|
||||||
|
|||||||
166
CHANGELOG.md
Normal file
166
CHANGELOG.md
Normal file
@@ -0,0 +1,166 @@
|
|||||||
|
# Changelog
|
||||||
|
|
||||||
|
All notable changes to this project will be documented in this file.
|
||||||
|
|
||||||
|
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
||||||
|
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
||||||
|
|
||||||
|
## [Unreleased]
|
||||||
|
|
||||||
|
## [16.1.2](https://github.com/topgrade-rs/topgrade/compare/v16.1.1...v16.1.2) - 2025-11-01
|
||||||
|
|
||||||
|
### Fixed
|
||||||
|
|
||||||
|
- *(release)* Fix cross-compilation for arm requiring glibc>=2.39 ([#1405](https://github.com/topgrade-rs/topgrade/pull/1405))
|
||||||
|
- *(release)* Fix FreeBSD build ([#1404](https://github.com/topgrade-rs/topgrade/pull/1404))
|
||||||
|
- *(release)* Fix FreeBSD build ([#1402](https://github.com/topgrade-rs/topgrade/pull/1402))
|
||||||
|
- *(release)* Fix manual workflow trigger ([#1401](https://github.com/topgrade-rs/topgrade/pull/1401))
|
||||||
|
- *(release)* Fix FreeBSD build and add manual workflow trigger ([#1399](https://github.com/topgrade-rs/topgrade/pull/1399))
|
||||||
|
|
||||||
|
### Other
|
||||||
|
|
||||||
|
- *(release)* Fix cross trying to fmt ([#1403](https://github.com/topgrade-rs/topgrade/pull/1403))
|
||||||
|
|
||||||
|
## [16.1.1](https://github.com/topgrade-rs/topgrade/compare/v16.1.0...v16.1.1) - 2025-11-01
|
||||||
|
|
||||||
|
### Fixed
|
||||||
|
|
||||||
|
- *(typst)* Skip typst when self-update is disabled ([#1397](https://github.com/topgrade-rs/topgrade/pull/1397))
|
||||||
|
- *(release)* Fix winget release workflow ([#1395](https://github.com/topgrade-rs/topgrade/pull/1395))
|
||||||
|
- *(release)* Fix FreeBSD release ([#1393](https://github.com/topgrade-rs/topgrade/pull/1393))
|
||||||
|
- *(release)* Fix FreeBSD release ([#1391](https://github.com/topgrade-rs/topgrade/pull/1391))
|
||||||
|
|
||||||
|
### Other
|
||||||
|
|
||||||
|
- Update from deprecated macos-13 to macos-15-intel ([#1394](https://github.com/topgrade-rs/topgrade/pull/1394))
|
||||||
|
|
||||||
|
## [16.1.0](https://github.com/topgrade-rs/topgrade/compare/v16.0.4...v16.1.0) - 2025-10-31
|
||||||
|
|
||||||
|
### Added
|
||||||
|
|
||||||
|
- *(deb-get)* Skip non-deb-get packages by passing --dg-only ([#1386](https://github.com/topgrade-rs/topgrade/pull/1386))
|
||||||
|
- *(typst)* add typst step ([#1374](https://github.com/topgrade-rs/topgrade/pull/1374))
|
||||||
|
- *(step)* Add atuin step ([#1367](https://github.com/topgrade-rs/topgrade/pull/1367))
|
||||||
|
- *(nix)* support upgrading Determinate Nix ([#1366](https://github.com/topgrade-rs/topgrade/pull/1366))
|
||||||
|
- *(sudo)* print warning if Windows Sudo is misconfigured
|
||||||
|
- *(sudo)* print warning if steps were skipped due to missing sudo
|
||||||
|
- *(sudo)* add SudoKind::Null
|
||||||
|
- detect and warn if running as root
|
||||||
|
- add `--no-tmux` flag ([#1328](https://github.com/topgrade-rs/topgrade/pull/1328))
|
||||||
|
- add step for mandb - user and system (update man entries) ([#1319](https://github.com/topgrade-rs/topgrade/pull/1319))
|
||||||
|
- support for pkgfile ([#1306](https://github.com/topgrade-rs/topgrade/pull/1306))
|
||||||
|
- add "show_skipped" option in config file #1280 ([#1286](https://github.com/topgrade-rs/topgrade/pull/1286))
|
||||||
|
- fix typos ([#1221](https://github.com/topgrade-rs/topgrade/pull/1221))
|
||||||
|
- *(conda)* allow configuring additional envs to update ([#1048](https://github.com/topgrade-rs/topgrade/pull/1048))
|
||||||
|
- *(step)* nix-helper ([#1045](https://github.com/topgrade-rs/topgrade/pull/1045))
|
||||||
|
- *(winget)* winget uses sudo when `[windows] winget_use_sudo = true` ([#1061](https://github.com/topgrade-rs/topgrade/pull/1061))
|
||||||
|
- suppress pixi release notes by default ([#1225](https://github.com/topgrade-rs/topgrade/pull/1225))
|
||||||
|
|
||||||
|
### Fixed
|
||||||
|
|
||||||
|
- *(freshclam)* run with sudo when running without sudo fails ([#1118](https://github.com/topgrade-rs/topgrade/pull/1118))
|
||||||
|
- *(tldr)* move tldr to be a generic step ([#1370](https://github.com/topgrade-rs/topgrade/pull/1370))
|
||||||
|
- *(nix)* fix nix upgrade command selection for profiles in XDG_STATE_HOME ([#1354](https://github.com/topgrade-rs/topgrade/pull/1354))
|
||||||
|
- *(containers)* Docker update fails on M Macs due to platform / ([#1360](https://github.com/topgrade-rs/topgrade/pull/1360))
|
||||||
|
- *(sudo)* reorder require_sudo() after print_separator()
|
||||||
|
- *(sudo)* use require_sudo for windows commands
|
||||||
|
- *(sudo)* prevent sudo_command = "sudo" finding gsudo
|
||||||
|
- *(sudo)* set sudo flags depending on kind
|
||||||
|
- skip gcloud update step if component manager is disabled ([#1237](https://github.com/topgrade-rs/topgrade/pull/1237))
|
||||||
|
- *(i18n)* use double-quotes for translations with newlines
|
||||||
|
- *(powershell)* run microsoft_store command directly
|
||||||
|
- *(powershell)* remove mentions of USOClient
|
||||||
|
- *(powershell)* execution policy check breaks when run in pwsh
|
||||||
|
- *(powershell)* don't use sudo with Update-Module for pwsh
|
||||||
|
- *(powershell)* add -Command to module update cmdline
|
||||||
|
- *(tmux)* support all default `tpm` locations (xdg and both hardcoded locations) ([#1146](https://github.com/topgrade-rs/topgrade/pull/1146))
|
||||||
|
- fixed the German translation for "y/n/s/q" ([#1220](https://github.com/topgrade-rs/topgrade/pull/1220))
|
||||||
|
|
||||||
|
### Other
|
||||||
|
|
||||||
|
- *(release)* switch to release-plz ([#1333](https://github.com/topgrade-rs/topgrade/pull/1333))
|
||||||
|
- *(pre-commit)* Make pre-commit.ci use conventional commits ([#1388](https://github.com/topgrade-rs/topgrade/pull/1388))
|
||||||
|
- *(pre-commit)* pre-commit autoupdate ([#1383](https://github.com/topgrade-rs/topgrade/pull/1383))
|
||||||
|
- *(deps)* bump actions/upload-artifact from 4.6.2 to 5.0.0 ([#1382](https://github.com/topgrade-rs/topgrade/pull/1382))
|
||||||
|
- *(deps)* bump github/codeql-action from 4.30.9 to 4.31.0 ([#1379](https://github.com/topgrade-rs/topgrade/pull/1379))
|
||||||
|
- *(deps)* bump actions/download-artifact from 5.0.0 to 6.0.0 ([#1380](https://github.com/topgrade-rs/topgrade/pull/1380))
|
||||||
|
- *(deps)* bump taiki-e/install-action from 2.62.33 to 2.62.38 ([#1381](https://github.com/topgrade-rs/topgrade/pull/1381))
|
||||||
|
- *(pre-commit)* Fix pre-commit-config.yaml ([#1378](https://github.com/topgrade-rs/topgrade/pull/1378))
|
||||||
|
- *(release)* Add .deb auto completion script ([#1353](https://github.com/topgrade-rs/topgrade/pull/1353))
|
||||||
|
- *(deps)* bump github/codeql-action from 4.30.8 to 4.30.9 ([#1369](https://github.com/topgrade-rs/topgrade/pull/1369))
|
||||||
|
- *(deps)* bump taiki-e/install-action from 2.62.28 to 2.62.33 ([#1368](https://github.com/topgrade-rs/topgrade/pull/1368))
|
||||||
|
- *(deps)* bump actions/dependency-review-action from 4.8.0 to 4.8.1 ([#1362](https://github.com/topgrade-rs/topgrade/pull/1362))
|
||||||
|
- *(deps)* bump softprops/action-gh-release from 2.3.4 to 2.4.1 ([#1364](https://github.com/topgrade-rs/topgrade/pull/1364))
|
||||||
|
- *(deps)* bump taiki-e/install-action from 2.62.21 to 2.62.28 ([#1363](https://github.com/topgrade-rs/topgrade/pull/1363))
|
||||||
|
- *(deps)* bump github/codeql-action from 3.30.6 to 4.30.8 ([#1365](https://github.com/topgrade-rs/topgrade/pull/1365))
|
||||||
|
- *(deps)* bump github/codeql-action from 3.30.5 to 3.30.6 ([#1355](https://github.com/topgrade-rs/topgrade/pull/1355))
|
||||||
|
- *(deps)* bump softprops/action-gh-release from 2.3.3 to 2.3.4 ([#1356](https://github.com/topgrade-rs/topgrade/pull/1356))
|
||||||
|
- *(deps)* bump taiki-e/install-action from 2.62.13 to 2.62.21 ([#1357](https://github.com/topgrade-rs/topgrade/pull/1357))
|
||||||
|
- *(deps)* bump ossf/scorecard-action from 2.4.2 to 2.4.3 ([#1358](https://github.com/topgrade-rs/topgrade/pull/1358))
|
||||||
|
- *(deps)* bump actions/dependency-review-action from 4.7.3 to 4.8.0 ([#1350](https://github.com/topgrade-rs/topgrade/pull/1350))
|
||||||
|
- *(deps)* bump github/codeql-action from 3.30.3 to 3.30.5 ([#1349](https://github.com/topgrade-rs/topgrade/pull/1349))
|
||||||
|
- *(deps)* bump taiki-e/install-action from 2.62.1 to 2.62.13 ([#1351](https://github.com/topgrade-rs/topgrade/pull/1351))
|
||||||
|
- *(deps)* bump actions/cache from 4.2.4 to 4.3.0 ([#1352](https://github.com/topgrade-rs/topgrade/pull/1352))
|
||||||
|
- Fix WSL distribution name cleanup ([#1348](https://github.com/topgrade-rs/topgrade/pull/1348))
|
||||||
|
- *(pyproject)* mark version as dynamic ([#1347](https://github.com/topgrade-rs/topgrade/pull/1347))
|
||||||
|
- *(deps)* replace winapi with windows
|
||||||
|
- *(sudo)* rename interactive to login_shell
|
||||||
|
- Fix "WSL already reported" panic ([#1344](https://github.com/topgrade-rs/topgrade/pull/1344))
|
||||||
|
- Move step logic out of Powershell struct ([#1345](https://github.com/topgrade-rs/topgrade/pull/1345))
|
||||||
|
- *(deps)* bump taiki-e/install-action from 2.61.5 to 2.62.1 ([#1335](https://github.com/topgrade-rs/topgrade/pull/1335))
|
||||||
|
- *(deps)* bump Swatinem/rust-cache from 2.8.0 to 2.8.1 ([#1336](https://github.com/topgrade-rs/topgrade/pull/1336))
|
||||||
|
- Fixes for #1188; custom_commands broken ([#1332](https://github.com/topgrade-rs/topgrade/pull/1332))
|
||||||
|
- use login shell when executing topgrade ([#1327](https://github.com/topgrade-rs/topgrade/pull/1327))
|
||||||
|
- *(deps)* bump taiki-e/install-action from 2.60.0 to 2.61.5 ([#1325](https://github.com/topgrade-rs/topgrade/pull/1325))
|
||||||
|
- *(deps)* bump github/codeql-action from 3.30.1 to 3.30.3 ([#1324](https://github.com/topgrade-rs/topgrade/pull/1324))
|
||||||
|
- *(pre-commit)* add typos with conservative excludes; no content changes ([#1317](https://github.com/topgrade-rs/topgrade/pull/1317))
|
||||||
|
- fix simple typos in code and comments (split var, whether, Extensions) ([#1318](https://github.com/topgrade-rs/topgrade/pull/1318))
|
||||||
|
- *(deps)* bump github/codeql-action from 3.29.11 to 3.30.1 ([#1301](https://github.com/topgrade-rs/topgrade/pull/1301))
|
||||||
|
- *(deps)* bump softprops/action-gh-release from 2.3.2 to 2.3.3 ([#1302](https://github.com/topgrade-rs/topgrade/pull/1302))
|
||||||
|
- *(deps)* bump taiki-e/install-action from 2.58.21 to 2.60.0 ([#1303](https://github.com/topgrade-rs/topgrade/pull/1303))
|
||||||
|
- *(deps)* bump actions/dependency-review-action from 4.7.2 to 4.7.3 ([#1304](https://github.com/topgrade-rs/topgrade/pull/1304))
|
||||||
|
- *(deps)* bump actions/attest-build-provenance from 2.4.0 to 3.0.0 ([#1305](https://github.com/topgrade-rs/topgrade/pull/1305))
|
||||||
|
- update tracing-subscriber to ~0.3.20 (ANSI escape injection fix, GHSA-xwfj-jgwm-7wp5) ([#1288](https://github.com/topgrade-rs/topgrade/pull/1288))
|
||||||
|
- *(deps)* bump github/codeql-action from 3.29.8 to 3.29.11 ([#1281](https://github.com/topgrade-rs/topgrade/pull/1281))
|
||||||
|
- *(deps)* bump actions/dependency-review-action from 4.7.1 to 4.7.2 ([#1282](https://github.com/topgrade-rs/topgrade/pull/1282))
|
||||||
|
- *(deps)* bump taiki-e/install-action from 2.58.9 to 2.58.21 ([#1283](https://github.com/topgrade-rs/topgrade/pull/1283))
|
||||||
|
- *(deps)* bump PyO3/maturin-action from 1.49.3 to 1.49.4 ([#1285](https://github.com/topgrade-rs/topgrade/pull/1285))
|
||||||
|
- *(deps)* bump actions/cache from 4.2.3 to 4.2.4 ([#1284](https://github.com/topgrade-rs/topgrade/pull/1284))
|
||||||
|
- Support "Insiders" versions of VSCode and VSCodium ([#1279](https://github.com/topgrade-rs/topgrade/pull/1279))
|
||||||
|
- Sudo preserve env list argument is `--preserve-env` ([#1276](https://github.com/topgrade-rs/topgrade/pull/1276))
|
||||||
|
- Clippy fixes from rust 1.91 nightly ([#1267](https://github.com/topgrade-rs/topgrade/pull/1267))
|
||||||
|
- *(deps)* bump actions/checkout from 4.2.2 to 5.0.0 ([#1264](https://github.com/topgrade-rs/topgrade/pull/1264))
|
||||||
|
- *(deps)* bump actions/download-artifact from 4.3.0 to 5.0.0 ([#1263](https://github.com/topgrade-rs/topgrade/pull/1263))
|
||||||
|
- *(deps)* bump taiki-e/install-action from 2.58.0 to 2.58.9 ([#1261](https://github.com/topgrade-rs/topgrade/pull/1261))
|
||||||
|
- *(deps)* bump ossf/scorecard-action from 2.4.0 to 2.4.2 ([#1262](https://github.com/topgrade-rs/topgrade/pull/1262))
|
||||||
|
- *(deps)* bump github/codeql-action from 3.29.5 to 3.29.8 ([#1265](https://github.com/topgrade-rs/topgrade/pull/1265))
|
||||||
|
- *(ci)* Dependabot, workflow security ([#1257](https://github.com/topgrade-rs/topgrade/pull/1257))
|
||||||
|
- replace once_cell crate with std equivalent ([#1260](https://github.com/topgrade-rs/topgrade/pull/1260))
|
||||||
|
- *(deps)* bump tokio from 1.38 to 1.47 ([#1256](https://github.com/topgrade-rs/topgrade/pull/1256))
|
||||||
|
- *(app.yml)* fix fr language #1248
|
||||||
|
- *(sudo)* add SudoKind::WinSudo
|
||||||
|
- *(sudo)* add SudoExecuteOpts builder functions and preserve_env enum
|
||||||
|
- *(yarn)* remove unnecessary Yarn::yarn field
|
||||||
|
- *(apt)* extract detect_apt() function
|
||||||
|
- route sudo usage through Sudo::execute*
|
||||||
|
- move RunType::execute to ExecutionContext
|
||||||
|
- *(powershell)* store powershell path directly
|
||||||
|
- *(powershell)* cleanup and simplify code
|
||||||
|
- Move step running into enum for dynamic ordering ([#1188](https://github.com/topgrade-rs/topgrade/pull/1188))
|
||||||
|
- Generate artifact attestations for release assets ([#1216](https://github.com/topgrade-rs/topgrade/pull/1216))
|
||||||
|
- windows update, use explicit reboot policy ([#1143](https://github.com/topgrade-rs/topgrade/pull/1143))
|
||||||
|
- add Discord invite link to README ([#1203](https://github.com/topgrade-rs/topgrade/pull/1203))
|
||||||
|
- Catch secondary uv self-update error ([#1201](https://github.com/topgrade-rs/topgrade/pull/1201))
|
||||||
|
- Handle another format change in asdf version ([#1194](https://github.com/topgrade-rs/topgrade/pull/1194))
|
||||||
|
- Preserve custom command order from config instead of sorting alphabetically ([#1182](https://github.com/topgrade-rs/topgrade/pull/1182))
|
||||||
|
- Add support for multiple binary names and idea having multiple binaries ([#1167](https://github.com/topgrade-rs/topgrade/pull/1167))
|
||||||
|
- fix the invalid action version ([#1185](https://github.com/topgrade-rs/topgrade/pull/1185))
|
||||||
|
- allow us to re-run AUR CI ([#1184](https://github.com/topgrade-rs/topgrade/pull/1184))
|
||||||
|
- Update Yazi upgrade step to use ya pkg. ([#1163](https://github.com/topgrade-rs/topgrade/pull/1163))
|
||||||
|
- use the new tag name and specify shell to bash ([#1183](https://github.com/topgrade-rs/topgrade/pull/1183))
|
||||||
|
- allow specifying tag when manually run 'create_release_assets.yml' ([#1180](https://github.com/topgrade-rs/topgrade/pull/1180))
|
||||||
|
- fix homebrew ci, remove duplicate trigger event ([#1179](https://github.com/topgrade-rs/topgrade/pull/1179))
|
||||||
|
- fix PyPI pipeline duplicate wheel name ([#1178](https://github.com/topgrade-rs/topgrade/pull/1178))
|
||||||
|
- add event workflow_dispatch to release pipelines ([#1177](https://github.com/topgrade-rs/topgrade/pull/1177))
|
||||||
|
- fix pipeline release to PyPI ([#1176](https://github.com/topgrade-rs/topgrade/pull/1176))
|
||||||
|
- Install rustfmt and clippy where necessary ([#1171](https://github.com/topgrade-rs/topgrade/pull/1171))
|
||||||
@@ -16,15 +16,15 @@ In `topgrade`'s term, package manager is called `step`.
|
|||||||
To add a new `step` to `topgrade`:
|
To add a new `step` to `topgrade`:
|
||||||
|
|
||||||
1. Add a new variant to
|
1. Add a new variant to
|
||||||
[`enum Step`](https://github.com/topgrade-rs/topgrade/blob/cb7adc8ced8a77addf2cb051d18bba9f202ab866/src/config.rs#L100)
|
[`enum Step`](https://github.com/topgrade-rs/topgrade/blob/main/src/step.rs)
|
||||||
|
|
||||||
```rust
|
```rust
|
||||||
pub enum Step {
|
pub enum Step {
|
||||||
// Existed steps
|
// Existing steps
|
||||||
// ...
|
// ...
|
||||||
|
|
||||||
// Your new step here!
|
// Your new step here!
|
||||||
// You may want it to be sorted alphabetically because that looks great:)
|
// Make sure it stays sorted alphabetically because that looks great :)
|
||||||
Xxx,
|
Xxx,
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
@@ -32,9 +32,9 @@ To add a new `step` to `topgrade`:
|
|||||||
2. Implement the update function
|
2. Implement the update function
|
||||||
|
|
||||||
You need to find the appropriate location where this update function goes, it should be
|
You need to find the appropriate location where this update function goes, it should be
|
||||||
a file under [`src/steps`](https://github.com/topgrade-rs/topgrade/tree/master/src/steps),
|
a file under [`src/steps`](https://github.com/topgrade-rs/topgrade/tree/main/src/steps),
|
||||||
the file names are self-explanatory, for example, `step`s related to `zsh` are
|
the file names are self-explanatory, for example, `step`s related to `zsh` are
|
||||||
placed in [`steps/zsh.rs`](https://github.com/topgrade-rs/topgrade/blob/master/src/steps/zsh.rs).
|
placed in [`steps/zsh.rs`](https://github.com/topgrade-rs/topgrade/blob/main/src/steps/zsh.rs).
|
||||||
|
|
||||||
Then you implement the update function, and put it in the file where it belongs.
|
Then you implement the update function, and put it in the file where it belongs.
|
||||||
|
|
||||||
@@ -47,8 +47,7 @@ To add a new `step` to `topgrade`:
|
|||||||
print_separator("xxx");
|
print_separator("xxx");
|
||||||
|
|
||||||
// Invoke the new step to get things updated!
|
// Invoke the new step to get things updated!
|
||||||
ctx.run_type()
|
ctx.execute(xxx)
|
||||||
.execute(xxx)
|
|
||||||
.arg(/* args required by this step */)
|
.arg(/* args required by this step */)
|
||||||
.status_checked()
|
.status_checked()
|
||||||
}
|
}
|
||||||
@@ -61,24 +60,24 @@ To add a new `step` to `topgrade`:
|
|||||||
[here](https://github.com/topgrade-rs/topgrade/blob/7e48c5dedcfd5d0124bb9f39079a03e27ed23886/src/main.rs#L201-L219)).
|
[here](https://github.com/topgrade-rs/topgrade/blob/7e48c5dedcfd5d0124bb9f39079a03e27ed23886/src/main.rs#L201-L219)).
|
||||||
|
|
||||||
Update function would usually do 3 things:
|
Update function would usually do 3 things:
|
||||||
1. Check if the step is installed
|
1. Check if the step is installed
|
||||||
2. Output the Separator
|
2. Output the Separator
|
||||||
3. Invoke the step
|
3. Invoke the step
|
||||||
|
|
||||||
Still, this is sufficient for most tools, but you may need some extra stuff
|
Still, this is sufficient for most tools, but you may need some extra stuff
|
||||||
with complicated `step`.
|
with complicated `step`.
|
||||||
|
|
||||||
3. Finally, invoke that update function in `main.rs`
|
3. Add a match arm to `Step::run()`
|
||||||
|
|
||||||
```rust
|
```rust
|
||||||
runner.execute(Step::Xxx, "xxx", || ItsModule::run_xxx(&ctx))?;
|
Xxx => runner.execute(*self, "xxx", || ItsModule::run_xxx(ctx))?
|
||||||
```
|
```
|
||||||
|
|
||||||
We use [conditional compilation](https://doc.rust-lang.org/reference/conditional-compilation.html)
|
We use [conditional compilation](https://doc.rust-lang.org/reference/conditional-compilation.html)
|
||||||
to separate the steps, for example, for steps that are Linux-only, it goes
|
to separate the steps, for example, for steps that are Linux-only, it goes
|
||||||
like this:
|
like this:
|
||||||
|
|
||||||
```
|
```rust
|
||||||
#[cfg(target_os = "linux")]
|
#[cfg(target_os = "linux")]
|
||||||
{
|
{
|
||||||
// Xxx is Linux-only
|
// Xxx is Linux-only
|
||||||
@@ -86,19 +85,25 @@ To add a new `step` to `topgrade`:
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
Congrats, you just added a new `step`:)
|
4. Finally, add the step to `default_steps()` in `step.rs`
|
||||||
|
```rust
|
||||||
|
steps.push(Xxx)
|
||||||
|
```
|
||||||
|
Try to keep the conditional compilation the same as in the above step 3.
|
||||||
|
|
||||||
|
Congrats, you just added a new `step` :)
|
||||||
|
|
||||||
## Modification to the configuration entries
|
## Modification to the configuration entries
|
||||||
|
|
||||||
If your PR has the configuration options
|
If your PR has the configuration options
|
||||||
(in [`src/config.rs`](https://github.com/topgrade-rs/topgrade/blob/master/src/config.rs))
|
(in [`src/config.rs`](https://github.com/topgrade-rs/topgrade/blob/main/src/config.rs))
|
||||||
modified:
|
modified:
|
||||||
|
|
||||||
1. Adding new options
|
1. Adding new options
|
||||||
2. Changing the existing options
|
2. Changing the existing options
|
||||||
|
|
||||||
Be sure to apply your changes to
|
Be sure to apply your changes to
|
||||||
[`config.example.toml`](https://github.com/topgrade-rs/topgrade/blob/master/config.example.toml),
|
[`config.example.toml`](https://github.com/topgrade-rs/topgrade/blob/main/config.example.toml),
|
||||||
and have some basic documentations guiding user how to use these options.
|
and have some basic documentations guiding user how to use these options.
|
||||||
|
|
||||||
## Breaking changes
|
## Breaking changes
|
||||||
@@ -129,21 +134,21 @@ $ cargo test
|
|||||||
|
|
||||||
Don't worry about other platforms, we have most of them covered in our CI.
|
Don't worry about other platforms, we have most of them covered in our CI.
|
||||||
|
|
||||||
## I18n
|
## I18n
|
||||||
|
|
||||||
If your PR introduces user-facing messages, we need to ensure they are translated.
|
If your PR introduces user-facing messages, we need to ensure they are translated.
|
||||||
Please add the translations to [`locales/app.yml`][app_yml]. For simple messages
|
Please add the translations to [`locales/app.yml`][app_yml]. For simple messages
|
||||||
without arguments (e.g., "hello world"), we can simply translate them according
|
without arguments (e.g., "hello world"), we can simply translate them according
|
||||||
(Tip: ChatGPT or similar LLMs is good at translation). If a message contains
|
(Tip: ChatGPT or similar LLMs is good at translation). If a message contains
|
||||||
arguments, e.g., "hello <NAME>", please follow this convention:
|
arguments, e.g., "hello <NAME>", please follow this convention:
|
||||||
|
|
||||||
```yml
|
```yml
|
||||||
"hello {name}": # key
|
"hello {name}": # key
|
||||||
en: "hello %{name}" # translation
|
en: "hello %{name}" # translation
|
||||||
```
|
```
|
||||||
|
|
||||||
Arguments in the key should be in format `{argument_name}`, and they will have
|
Arguments in the key should be in format `{argument_name}`, and they will have
|
||||||
a preceeding `%` when used in translations.
|
a preceding `%` when used in translations.
|
||||||
|
|
||||||
[app_yml]: https://github.com/topgrade-rs/topgrade/blob/main/locales/app.yml
|
[app_yml]: https://github.com/topgrade-rs/topgrade/blob/main/locales/app.yml
|
||||||
|
|
||||||
|
|||||||
352
Cargo.lock
generated
352
Cargo.lock
generated
@@ -1062,8 +1062,8 @@ dependencies = [
|
|||||||
"aho-corasick",
|
"aho-corasick",
|
||||||
"bstr",
|
"bstr",
|
||||||
"log",
|
"log",
|
||||||
"regex-automata 0.4.7",
|
"regex-automata",
|
||||||
"regex-syntax 0.8.4",
|
"regex-syntax",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -1089,6 +1089,12 @@ version = "0.14.5"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1"
|
checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "hashbrown"
|
||||||
|
version = "0.15.4"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "5971ac85611da7067dbfcabef3c70ebb5606018acd9e2a3903a0da507521e0d5"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "heck"
|
name = "heck"
|
||||||
version = "0.5.0"
|
version = "0.5.0"
|
||||||
@@ -1205,7 +1211,7 @@ dependencies = [
|
|||||||
"http-body",
|
"http-body",
|
||||||
"hyper",
|
"hyper",
|
||||||
"pin-project-lite",
|
"pin-project-lite",
|
||||||
"socket2",
|
"socket2 0.5.7",
|
||||||
"tokio",
|
"tokio",
|
||||||
"tower",
|
"tower",
|
||||||
"tower-service",
|
"tower-service",
|
||||||
@@ -1375,7 +1381,7 @@ dependencies = [
|
|||||||
"globset",
|
"globset",
|
||||||
"log",
|
"log",
|
||||||
"memchr",
|
"memchr",
|
||||||
"regex-automata 0.4.7",
|
"regex-automata",
|
||||||
"same-file",
|
"same-file",
|
||||||
"walkdir",
|
"walkdir",
|
||||||
"winapi-util",
|
"winapi-util",
|
||||||
@@ -1399,12 +1405,13 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "indexmap"
|
name = "indexmap"
|
||||||
version = "2.2.6"
|
version = "2.9.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "168fb715dda47215e360912c096649d23d58bf392ac62f73919e831745e40f26"
|
checksum = "cea70ddb795996207ad57735b50c5982d8844f38ba9ee5f1aedcfb708a2aa11e"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"equivalent",
|
"equivalent",
|
||||||
"hashbrown 0.14.5",
|
"hashbrown 0.15.4",
|
||||||
|
"serde",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -1429,12 +1436,32 @@ dependencies = [
|
|||||||
"cfg-if",
|
"cfg-if",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "io-uring"
|
||||||
|
version = "0.7.9"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "d93587f37623a1a17d94ef2bc9ada592f5465fe7732084ab7beefabe5c77c0c4"
|
||||||
|
dependencies = [
|
||||||
|
"bitflags 2.5.0",
|
||||||
|
"cfg-if",
|
||||||
|
"libc",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "ipnet"
|
name = "ipnet"
|
||||||
version = "2.9.0"
|
version = "2.9.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "8f518f335dce6725a761382244631d86cf0ccb2863413590b31338feb467f9c3"
|
checksum = "8f518f335dce6725a761382244631d86cf0ccb2863413590b31338feb467f9c3"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "is_elevated"
|
||||||
|
version = "0.1.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "5299060ff5db63e788015dcb9525ad9b84f4fd9717ed2cbdeba5018cbf42f9b5"
|
||||||
|
dependencies = [
|
||||||
|
"winapi",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "is_terminal_polyfill"
|
name = "is_terminal_polyfill"
|
||||||
version = "1.70.0"
|
version = "1.70.0"
|
||||||
@@ -1449,9 +1476,9 @@ checksum = "49f1f14873335454500d59611f1cf4a4b0f786f9ac11f4312a78e4cf2566695b"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "jetbrains-toolbox-updater"
|
name = "jetbrains-toolbox-updater"
|
||||||
version = "1.4.0"
|
version = "5.0.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "b9d86b38fee698b3f63c9772fe2832d03a84e0724e409d499517c8a102949717"
|
checksum = "5c6bb35a4c18ced364ba2a3952bf5ca2b9231451974f5c2a4c8fa14f300a545b"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"dirs 6.0.0",
|
"dirs 6.0.0",
|
||||||
"json",
|
"json",
|
||||||
@@ -1481,9 +1508,9 @@ checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "libc"
|
name = "libc"
|
||||||
version = "0.2.170"
|
version = "0.2.172"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "875b3680cb2f8f71bdcf9a30f38d48282f5d3c95cbf9b3fa57269bb5d5c06828"
|
checksum = "d750af042f7ef4f724306de029d18836c26c1765a54a6a3f094cbd23a7267ffa"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "libredox"
|
name = "libredox"
|
||||||
@@ -1543,11 +1570,11 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "matchers"
|
name = "matchers"
|
||||||
version = "0.1.0"
|
version = "0.2.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "8263075bb86c5a1b1427b5ae862e8889656f126e9f77c484496e8b47cf5c5558"
|
checksum = "d1525a2a28c7f4fa0fc98bb91ae755d1e2d1505079e05539e35bc876b5d65ae9"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"regex-automata 0.1.10",
|
"regex-automata",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -1604,13 +1631,13 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "mio"
|
name = "mio"
|
||||||
version = "0.8.11"
|
version = "1.0.4"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "a4a650543ca06a924e8b371db273b2756685faae30f8487da1b56505a8f78b0c"
|
checksum = "78bed444cc8a2160f01cbcf811ef18cac863ad68ae8ca62092e8db51d51c761c"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"libc",
|
"libc",
|
||||||
"wasi",
|
"wasi",
|
||||||
"windows-sys 0.48.0",
|
"windows-sys 0.59.0",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -1671,12 +1698,11 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "nu-ansi-term"
|
name = "nu-ansi-term"
|
||||||
version = "0.46.0"
|
version = "0.50.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "77a8165726e8236064dbb45459242600304b42a5ea24ee2948e18e023bf7ba84"
|
checksum = "d4a28e057d01f97e61255210fcff094d74ed0466038633e95017f5beb68e4399"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"overload",
|
"windows-sys 0.52.0",
|
||||||
"winapi",
|
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -1694,16 +1720,6 @@ dependencies = [
|
|||||||
"autocfg",
|
"autocfg",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "num_cpus"
|
|
||||||
version = "1.16.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "4161fcb6d602d4d2081af7c3a45852d875a03dd337a6bfdd6e06407b61342a43"
|
|
||||||
dependencies = [
|
|
||||||
"hermit-abi",
|
|
||||||
"libc",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "number_prefix"
|
name = "number_prefix"
|
||||||
version = "0.4.0"
|
version = "0.4.0"
|
||||||
@@ -1730,6 +1746,15 @@ dependencies = [
|
|||||||
"objc_id",
|
"objc_id",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "objc2-core-foundation"
|
||||||
|
version = "0.3.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "daeaf60f25471d26948a1c2f840e3f7d86f4109e3af4e8e4b5cd70c39690d925"
|
||||||
|
dependencies = [
|
||||||
|
"bitflags 2.5.0",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "objc_id"
|
name = "objc_id"
|
||||||
version = "0.1.1"
|
version = "0.1.1"
|
||||||
@@ -1780,12 +1805,6 @@ dependencies = [
|
|||||||
"pin-project-lite",
|
"pin-project-lite",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "overload"
|
|
||||||
version = "0.1.1"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "b15813163c1d831bf4a13c3610c05c0d03b39feb07f7e09fa234dac9b15aaf39"
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "owo-colors"
|
name = "owo-colors"
|
||||||
version = "3.5.0"
|
version = "3.5.0"
|
||||||
@@ -2002,26 +2021,6 @@ 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"
|
||||||
@@ -2061,17 +2060,8 @@ checksum = "b91213439dad192326a0d7c6ee3955910425f441d7038e0d6933b0aec5c4517f"
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"aho-corasick",
|
"aho-corasick",
|
||||||
"memchr",
|
"memchr",
|
||||||
"regex-automata 0.4.7",
|
"regex-automata",
|
||||||
"regex-syntax 0.8.4",
|
"regex-syntax",
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "regex-automata"
|
|
||||||
version = "0.1.10"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "6c230d73fb8d8c1b9c0b3135c5142a8acee3a0558fb8db5cf1cb65f8d7862132"
|
|
||||||
dependencies = [
|
|
||||||
"regex-syntax 0.6.29",
|
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -2082,7 +2072,7 @@ checksum = "38caf58cc5ef2fed281f89292ef23f6365465ed9a41b7a7754eb4e26496c92df"
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"aho-corasick",
|
"aho-corasick",
|
||||||
"memchr",
|
"memchr",
|
||||||
"regex-syntax 0.8.4",
|
"regex-syntax",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -2094,12 +2084,6 @@ dependencies = [
|
|||||||
"regex",
|
"regex",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "regex-syntax"
|
|
||||||
version = "0.6.29"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "f162c6dd7b008981e4d40210aca20b4bd0f9b60ca9271061b07f78537722f2e1"
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "regex-syntax"
|
name = "regex-syntax"
|
||||||
version = "0.8.4"
|
version = "0.8.4"
|
||||||
@@ -2363,18 +2347,28 @@ checksum = "61697e0a1c7e512e84a621326239844a24d8207b4669b41bc18b32ea5cbf988b"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "serde"
|
name = "serde"
|
||||||
version = "1.0.203"
|
version = "1.0.228"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "7253ab4de971e72fb7be983802300c30b5a7f0c2e56fab8abfc6a214307c0094"
|
checksum = "9a8e94ea7f378bd32cbbd37198a4a91436180c5bb472411e48b5ec2e2124ae9e"
|
||||||
|
dependencies = [
|
||||||
|
"serde_core",
|
||||||
|
"serde_derive",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "serde_core"
|
||||||
|
version = "1.0.228"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "41d385c7d4ca58e59fc732af25c3983b67ac852c1a25000afe1175de458b67ad"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"serde_derive",
|
"serde_derive",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "serde_derive"
|
name = "serde_derive"
|
||||||
version = "1.0.203"
|
version = "1.0.228"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "500cbc0ebeb6f46627f50f3f5811ccf6bf00643be300b4c3eabc0ef55dc5b5ba"
|
checksum = "d540f220d3187173da220f885ab66608367b6574e925011a9353e4badda91d79"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
@@ -2383,13 +2377,15 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "serde_json"
|
name = "serde_json"
|
||||||
version = "1.0.117"
|
version = "1.0.145"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "455182ea6142b14f93f4bc5320a2b31c1f266b66a4a5c858b013302a5d8cbfc3"
|
checksum = "402a6f66d8c709116cf22f558eab210f5a50187f702eb4d7e5ef38d9a7f1c79c"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"itoa",
|
"itoa",
|
||||||
|
"memchr",
|
||||||
"ryu",
|
"ryu",
|
||||||
"serde",
|
"serde",
|
||||||
|
"serde_core",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -2532,6 +2528,16 @@ dependencies = [
|
|||||||
"windows-sys 0.52.0",
|
"windows-sys 0.52.0",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "socket2"
|
||||||
|
version = "0.6.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "233504af464074f9d066d7b5416c5f9b894a5862a6506e306f7b816cdd6f1807"
|
||||||
|
dependencies = [
|
||||||
|
"libc",
|
||||||
|
"windows-sys 0.59.0",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "spki"
|
name = "spki"
|
||||||
version = "0.7.3"
|
version = "0.7.3"
|
||||||
@@ -2638,16 +2644,15 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "sysinfo"
|
name = "sysinfo"
|
||||||
version = "0.33.1"
|
version = "0.34.2"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "4fc858248ea01b66f19d8e8a6d55f41deaf91e9d495246fd01368d99935c6c01"
|
checksum = "a4b93974b3d3aeaa036504b8eefd4c039dced109171c1ae973f1dc63b2c7e4b2"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"core-foundation-sys",
|
|
||||||
"libc",
|
"libc",
|
||||||
"memchr",
|
"memchr",
|
||||||
"ntapi",
|
"ntapi",
|
||||||
"rayon",
|
"objc2-core-foundation",
|
||||||
"windows",
|
"windows 0.56.0",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -2668,7 +2673,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||||||
checksum = "f89f5fb70d6f62381f5d9b2ba9008196150b40b75f3068eb24faeddf1c686871"
|
checksum = "f89f5fb70d6f62381f5d9b2ba9008196150b40b75f3068eb24faeddf1c686871"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"quick-xml 0.31.0",
|
"quick-xml 0.31.0",
|
||||||
"windows",
|
"windows 0.56.0",
|
||||||
"windows-version",
|
"windows-version",
|
||||||
]
|
]
|
||||||
|
|
||||||
@@ -2786,19 +2791,20 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "tokio"
|
name = "tokio"
|
||||||
version = "1.38.0"
|
version = "1.47.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "ba4f4a02a7a80d6f274636f0aa95c7e383b912d41fe721a31f29e29698585a4a"
|
checksum = "89e49afdadebb872d3145a5638b59eb0691ea23e46ca484037cfab3b76b95038"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"backtrace",
|
"backtrace",
|
||||||
"bytes",
|
"bytes",
|
||||||
|
"io-uring",
|
||||||
"libc",
|
"libc",
|
||||||
"mio",
|
"mio",
|
||||||
"num_cpus",
|
|
||||||
"pin-project-lite",
|
"pin-project-lite",
|
||||||
"signal-hook-registry",
|
"signal-hook-registry",
|
||||||
"socket2",
|
"slab",
|
||||||
"windows-sys 0.48.0",
|
"socket2 0.6.0",
|
||||||
|
"windows-sys 0.59.0",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -2851,7 +2857,7 @@ version = "0.19.15"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "1b5bb770da30e5cbfde35a2d7b9b8a2c4b8ef89548a7a6aeab5c9a576e3e7421"
|
checksum = "1b5bb770da30e5cbfde35a2d7b9b8a2c4b8ef89548a7a6aeab5c9a576e3e7421"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"indexmap 2.2.6",
|
"indexmap 2.9.0",
|
||||||
"serde",
|
"serde",
|
||||||
"serde_spanned",
|
"serde_spanned",
|
||||||
"toml_datetime",
|
"toml_datetime",
|
||||||
@@ -2864,7 +2870,7 @@ version = "0.21.1"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "6a8534fd7f78b5405e860340ad6575217ce99f38d4d5c8f2442cb5ecb50090e1"
|
checksum = "6a8534fd7f78b5405e860340ad6575217ce99f38d4d5c8f2442cb5ecb50090e1"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"indexmap 2.2.6",
|
"indexmap 2.9.0",
|
||||||
"toml_datetime",
|
"toml_datetime",
|
||||||
"winnow 0.5.40",
|
"winnow 0.5.40",
|
||||||
]
|
]
|
||||||
@@ -2875,7 +2881,7 @@ version = "0.22.14"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "f21c7aaf97f1bd9ca9d4f9e73b0a6c74bd5afef56f2bc931943a6e1c37e04e38"
|
checksum = "f21c7aaf97f1bd9ca9d4f9e73b0a6c74bd5afef56f2bc931943a6e1c37e04e38"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"indexmap 2.2.6",
|
"indexmap 2.9.0",
|
||||||
"serde",
|
"serde",
|
||||||
"serde_spanned",
|
"serde_spanned",
|
||||||
"toml_datetime",
|
"toml_datetime",
|
||||||
@@ -2884,7 +2890,7 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "topgrade"
|
name = "topgrade"
|
||||||
version = "16.0.3"
|
version = "16.1.2"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"cfg-if",
|
"cfg-if",
|
||||||
"chrono",
|
"chrono",
|
||||||
@@ -2897,12 +2903,12 @@ dependencies = [
|
|||||||
"futures",
|
"futures",
|
||||||
"glob",
|
"glob",
|
||||||
"home",
|
"home",
|
||||||
|
"indexmap 2.9.0",
|
||||||
|
"is_elevated",
|
||||||
"jetbrains-toolbox-updater",
|
"jetbrains-toolbox-updater",
|
||||||
"lazy_static",
|
|
||||||
"merge",
|
"merge",
|
||||||
"nix 0.29.0",
|
"nix 0.29.0",
|
||||||
"notify-rust",
|
"notify-rust",
|
||||||
"once_cell",
|
|
||||||
"parselnk",
|
"parselnk",
|
||||||
"regex",
|
"regex",
|
||||||
"regex-split",
|
"regex-split",
|
||||||
@@ -2911,6 +2917,7 @@ dependencies = [
|
|||||||
"self_update",
|
"self_update",
|
||||||
"semver",
|
"semver",
|
||||||
"serde",
|
"serde",
|
||||||
|
"serde_json",
|
||||||
"shell-words",
|
"shell-words",
|
||||||
"shellexpand",
|
"shellexpand",
|
||||||
"strum",
|
"strum",
|
||||||
@@ -2924,7 +2931,8 @@ dependencies = [
|
|||||||
"walkdir",
|
"walkdir",
|
||||||
"which",
|
"which",
|
||||||
"wildmatch",
|
"wildmatch",
|
||||||
"winapi",
|
"windows 0.62.0",
|
||||||
|
"windows-registry",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -2956,9 +2964,9 @@ checksum = "b6bc1c9ce2b5135ac7f93c72918fc37feb872bdc6a5533a8b85eb4b86bfdae52"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "tracing"
|
name = "tracing"
|
||||||
version = "0.1.40"
|
version = "0.1.41"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "c3523ab5a71916ccf420eebdf5521fcef02141234bbc0b8a49f2fdc4544364ef"
|
checksum = "784e0ac535deb450455cbfa28a6f0df145ea1bb7ae51b821cf5e7927fdcfbdd0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"log",
|
"log",
|
||||||
"pin-project-lite",
|
"pin-project-lite",
|
||||||
@@ -2968,9 +2976,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "tracing-attributes"
|
name = "tracing-attributes"
|
||||||
version = "0.1.27"
|
version = "0.1.30"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "34704c8d6ebcbc939824180af020566b01a7c01f80641264eba0999f6c2b6be7"
|
checksum = "81383ab64e72a7a8b8e13130c49e3dab29def6d0c7d76a03087b3cf71c5c6903"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
@@ -2979,9 +2987,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "tracing-core"
|
name = "tracing-core"
|
||||||
version = "0.1.32"
|
version = "0.1.34"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "c06d3da6113f116aaee68e4d601191614c9053067f9ab7f6edbcb161237daa54"
|
checksum = "b9d12581f227e93f094d3af2ae690a574abb8a2b9b7a96e7cfe9647b2b617678"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"once_cell",
|
"once_cell",
|
||||||
"valuable",
|
"valuable",
|
||||||
@@ -3010,14 +3018,14 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "tracing-subscriber"
|
name = "tracing-subscriber"
|
||||||
version = "0.3.18"
|
version = "0.3.20"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "ad0f048c97dbd9faa9b7df56362b8ebcaa52adb06b498c050d2f4e32f90a7a8b"
|
checksum = "2054a14f5307d601f88daf0553e1cbf472acc4f2c51afab632431cdcd72124d5"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"matchers",
|
"matchers",
|
||||||
"nu-ansi-term",
|
"nu-ansi-term",
|
||||||
"once_cell",
|
"once_cell",
|
||||||
"regex",
|
"regex-automata",
|
||||||
"sharded-slab",
|
"sharded-slab",
|
||||||
"smallvec",
|
"smallvec",
|
||||||
"thread_local",
|
"thread_local",
|
||||||
@@ -3307,6 +3315,28 @@ dependencies = [
|
|||||||
"windows-targets 0.52.6",
|
"windows-targets 0.52.6",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "windows"
|
||||||
|
version = "0.62.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "9579d0e6970fd5250aa29aba5994052385ff55cf7b28a059e484bb79ea842e42"
|
||||||
|
dependencies = [
|
||||||
|
"windows-collections",
|
||||||
|
"windows-core 0.62.0",
|
||||||
|
"windows-future",
|
||||||
|
"windows-link",
|
||||||
|
"windows-numerics",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "windows-collections"
|
||||||
|
version = "0.3.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "a90dd7a7b86859ec4cdf864658b311545ef19dbcf17a672b52ab7cefe80c336f"
|
||||||
|
dependencies = [
|
||||||
|
"windows-core 0.62.0",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "windows-core"
|
name = "windows-core"
|
||||||
version = "0.52.0"
|
version = "0.52.0"
|
||||||
@@ -3322,12 +3352,36 @@ version = "0.56.0"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "4698e52ed2d08f8658ab0c39512a7c00ee5fe2688c65f8c0a4f06750d729f2a6"
|
checksum = "4698e52ed2d08f8658ab0c39512a7c00ee5fe2688c65f8c0a4f06750d729f2a6"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"windows-implement",
|
"windows-implement 0.56.0",
|
||||||
"windows-interface",
|
"windows-interface 0.56.0",
|
||||||
"windows-result",
|
"windows-result 0.1.2",
|
||||||
"windows-targets 0.52.6",
|
"windows-targets 0.52.6",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "windows-core"
|
||||||
|
version = "0.62.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "57fe7168f7de578d2d8a05b07fd61870d2e73b4020e9f49aa00da8471723497c"
|
||||||
|
dependencies = [
|
||||||
|
"windows-implement 0.60.0",
|
||||||
|
"windows-interface 0.59.1",
|
||||||
|
"windows-link",
|
||||||
|
"windows-result 0.4.0",
|
||||||
|
"windows-strings",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "windows-future"
|
||||||
|
version = "0.3.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "b2194dee901458cb79e1148a4e9aac2b164cc95fa431891e7b296ff0b2f1d8a6"
|
||||||
|
dependencies = [
|
||||||
|
"windows-core 0.62.0",
|
||||||
|
"windows-link",
|
||||||
|
"windows-threading",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "windows-implement"
|
name = "windows-implement"
|
||||||
version = "0.56.0"
|
version = "0.56.0"
|
||||||
@@ -3339,6 +3393,17 @@ dependencies = [
|
|||||||
"syn 2.0.99",
|
"syn 2.0.99",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "windows-implement"
|
||||||
|
version = "0.60.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "a47fddd13af08290e67f4acabf4b459f647552718f683a7b415d290ac744a836"
|
||||||
|
dependencies = [
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"syn 2.0.99",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "windows-interface"
|
name = "windows-interface"
|
||||||
version = "0.56.0"
|
version = "0.56.0"
|
||||||
@@ -3350,6 +3415,44 @@ dependencies = [
|
|||||||
"syn 2.0.99",
|
"syn 2.0.99",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "windows-interface"
|
||||||
|
version = "0.59.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "bd9211b69f8dcdfa817bfd14bf1c97c9188afa36f4750130fcdf3f400eca9fa8"
|
||||||
|
dependencies = [
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"syn 2.0.99",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "windows-link"
|
||||||
|
version = "0.2.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "45e46c0661abb7180e7b9c281db115305d49ca1709ab8242adf09666d2173c65"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "windows-numerics"
|
||||||
|
version = "0.3.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "2ce3498fe0aba81e62e477408383196b4b0363db5e0c27646f932676283b43d8"
|
||||||
|
dependencies = [
|
||||||
|
"windows-core 0.62.0",
|
||||||
|
"windows-link",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "windows-registry"
|
||||||
|
version = "0.6.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "3f91f87ce112ffb7275000ea98eb1940912c21c1567c9312fde20261f3eadd29"
|
||||||
|
dependencies = [
|
||||||
|
"windows-link",
|
||||||
|
"windows-result 0.4.0",
|
||||||
|
"windows-strings",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "windows-result"
|
name = "windows-result"
|
||||||
version = "0.1.2"
|
version = "0.1.2"
|
||||||
@@ -3359,6 +3462,24 @@ dependencies = [
|
|||||||
"windows-targets 0.52.6",
|
"windows-targets 0.52.6",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "windows-result"
|
||||||
|
version = "0.4.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "7084dcc306f89883455a206237404d3eaf961e5bd7e0f312f7c91f57eb44167f"
|
||||||
|
dependencies = [
|
||||||
|
"windows-link",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "windows-strings"
|
||||||
|
version = "0.5.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "7218c655a553b0bed4426cf54b20d7ba363ef543b52d515b3e48d7fd55318dda"
|
||||||
|
dependencies = [
|
||||||
|
"windows-link",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "windows-sys"
|
name = "windows-sys"
|
||||||
version = "0.48.0"
|
version = "0.48.0"
|
||||||
@@ -3417,6 +3538,15 @@ dependencies = [
|
|||||||
"windows_x86_64_msvc 0.52.6",
|
"windows_x86_64_msvc 0.52.6",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "windows-threading"
|
||||||
|
version = "0.2.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "ab47f085ad6932defa48855254c758cdd0e2f2d48e62a34118a268d8f345e118"
|
||||||
|
dependencies = [
|
||||||
|
"windows-link",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "windows-version"
|
name = "windows-version"
|
||||||
version = "0.1.1"
|
version = "0.1.1"
|
||||||
|
|||||||
27
Cargo.toml
27
Cargo.toml
@@ -6,7 +6,7 @@ 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.84.1"
|
rust-version = "1.84.1"
|
||||||
version = "16.0.3"
|
version = "16.1.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 = "2021"
|
||||||
@@ -23,7 +23,6 @@ path = "src/main.rs"
|
|||||||
[dependencies]
|
[dependencies]
|
||||||
home = "~0.5"
|
home = "~0.5"
|
||||||
etcetera = "~0.8"
|
etcetera = "~0.8"
|
||||||
once_cell = "~1.19"
|
|
||||||
serde = { version = "~1.0", features = ["derive"] }
|
serde = { version = "~1.0", features = ["derive"] }
|
||||||
toml = "0.8"
|
toml = "0.8"
|
||||||
which_crate = { version = "~6.0", package = "which" }
|
which_crate = { version = "~6.0", package = "which" }
|
||||||
@@ -33,28 +32,29 @@ clap_complete = "~4.5"
|
|||||||
clap_mangen = "~0.2"
|
clap_mangen = "~0.2"
|
||||||
walkdir = "~2.5"
|
walkdir = "~2.5"
|
||||||
console = "~0.15"
|
console = "~0.15"
|
||||||
lazy_static = "~1.4"
|
|
||||||
chrono = "~0.4"
|
chrono = "~0.4"
|
||||||
glob = "~0.3"
|
glob = "~0.3"
|
||||||
strum = { version = "~0.26", features = ["derive"] }
|
strum = { version = "~0.26", features = ["derive"] }
|
||||||
thiserror = "~1.0"
|
thiserror = "~1.0"
|
||||||
tempfile = "~3.10"
|
tempfile = "~3.10"
|
||||||
cfg-if = "~1.0"
|
cfg-if = "~1.0"
|
||||||
tokio = { version = "~1.38", features = ["process", "rt-multi-thread"] }
|
tokio = { version = "~1.47", features = ["process", "rt-multi-thread"] }
|
||||||
futures = "~0.3"
|
futures = "~0.3"
|
||||||
regex = "~1.10"
|
regex = "~1.10"
|
||||||
semver = "~1.0"
|
semver = "~1.0"
|
||||||
shell-words = "~1.1"
|
shell-words = "~1.1"
|
||||||
color-eyre = "~0.6"
|
color-eyre = "~0.6"
|
||||||
tracing = { version = "~0.1", features = ["attributes", "log"] }
|
tracing = { version = "~0.1", features = ["attributes", "log"] }
|
||||||
tracing-subscriber = { version = "~0.3", features = ["env-filter", "time"] }
|
tracing-subscriber = { version = "~0.3.20", features = ["env-filter", "time"] }
|
||||||
merge = "~0.1"
|
merge = "~0.1"
|
||||||
regex-split = "~0.1"
|
regex-split = "~0.1"
|
||||||
notify-rust = "~4.11"
|
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"
|
jetbrains-toolbox-updater = "5.0.0"
|
||||||
|
indexmap = { version = "2.9.0", features = ["serde"] }
|
||||||
|
serde_json = "1.0.145"
|
||||||
|
|
||||||
[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" }]
|
||||||
@@ -72,6 +72,15 @@ extended-description = "Keeping your system up to date usually involves invoking
|
|||||||
section = "utils"
|
section = "utils"
|
||||||
priority = "optional"
|
priority = "optional"
|
||||||
default-features = true
|
default-features = true
|
||||||
|
assets = [
|
||||||
|
["target/release/topgrade", "usr/bin/", "755"],
|
||||||
|
["README.md", "usr/share/doc/topgrade/README.md", "644"],
|
||||||
|
# The man page is automatically generated by topgrade's build process in CI, so
|
||||||
|
# these files aren't actually committed.
|
||||||
|
["deployment/deb/topgrade.bash", "usr/share/bash-completion/completions/topgrade", "644"],
|
||||||
|
["deployment/deb/topgrade.fish", "usr/share/fish/vendor_completions.d/topgrade.fish", "644"],
|
||||||
|
["deployment/deb/_topgrade", "usr/share/zsh/vendor-completions/", "644"],
|
||||||
|
]
|
||||||
|
|
||||||
[target.'cfg(unix)'.dependencies]
|
[target.'cfg(unix)'.dependencies]
|
||||||
nix = { version = "~0.29", features = ["hostname", "signal", "user"] }
|
nix = { version = "~0.29", features = ["hostname", "signal", "user"] }
|
||||||
@@ -79,9 +88,11 @@ rust-ini = "~0.21"
|
|||||||
self_update_crate = { version = "~0.40", default-features = false, optional = true, package = "self_update", features = ["archive-tar", "compression-flate2", "rustls"] }
|
self_update_crate = { version = "~0.40", default-features = false, optional = true, package = "self_update", features = ["archive-tar", "compression-flate2", "rustls"] }
|
||||||
|
|
||||||
[target.'cfg(windows)'.dependencies]
|
[target.'cfg(windows)'.dependencies]
|
||||||
self_update_crate = { version = "~0.40", default-features = false, optional = true, package = "self_update", features = ["archive-zip", "compression-zip-deflate", "rustls"] }
|
is_elevated = "~0.1"
|
||||||
winapi = "~0.3"
|
|
||||||
parselnk = "~0.1"
|
parselnk = "~0.1"
|
||||||
|
self_update_crate = { version = "~0.40", default-features = false, optional = true, package = "self_update", features = ["archive-zip", "compression-zip-deflate", "rustls"] }
|
||||||
|
windows = { version = "~0.62", features = ["Win32_System_Console"] }
|
||||||
|
windows-registry = "~0.6"
|
||||||
|
|
||||||
[profile.release]
|
[profile.release]
|
||||||
lto = true
|
lto = true
|
||||||
|
|||||||
11
README.md
11
README.md
@@ -2,7 +2,7 @@
|
|||||||
<h1>
|
<h1>
|
||||||
<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>
|
||||||
@@ -44,14 +44,14 @@ The compiled binaries contain a self-upgrading feature.
|
|||||||
|
|
||||||
Just run `topgrade`.
|
Just run `topgrade`.
|
||||||
|
|
||||||
## Configuration
|
## Configuration
|
||||||
|
|
||||||
See `config.example.toml` for an example configuration file.
|
See `config.example.toml` for an example configuration file.
|
||||||
|
|
||||||
## Migration and Breaking Changes
|
## Migration and Breaking Changes
|
||||||
|
|
||||||
Whenever there is a **breaking change**, the major version number will be bumped,
|
Whenever there is a **breaking change**, the major version number will be bumped,
|
||||||
and we will document these changes in the release note, please take a look at
|
and we will document these changes in the release note, please take a look at
|
||||||
it when updated to a major release.
|
it when updated to a major release.
|
||||||
|
|
||||||
> Got a question? Feel free to open an issue or discussion!
|
> Got a question? Feel free to open an issue or discussion!
|
||||||
@@ -110,3 +110,8 @@ See [CONTRIBUTING.md](https://github.com/topgrade-rs/topgrade/blob/master/CONTRI
|
|||||||
- [ ] Add a proper testing framework to the code base.
|
- [ ] Add a proper testing framework to the code base.
|
||||||
- [ ] Add unit tests for package managers.
|
- [ ] Add unit tests for package managers.
|
||||||
- [ ] Split up code into more maintainable parts, eg. putting every linux package manager in a own submodule of linux.rs.
|
- [ ] Split up code into more maintainable parts, eg. putting every linux package manager in a own submodule of linux.rs.
|
||||||
|
|
||||||
|
## Discord server
|
||||||
|
|
||||||
|
Welcome to [join](https://discord.gg/Q8HGGWundY) our Discord server if you want
|
||||||
|
to discuss Topgrade!
|
||||||
|
|||||||
@@ -1,19 +1,14 @@
|
|||||||
> This document lists the steps that lead to a successful release of Topgrade.
|
Non-major versions go via release-plz.
|
||||||
|
|
||||||
1. Open a PR that:
|
|
||||||
|
|
||||||
> Here is an [Example PR](https://github.com/topgrade-rs/topgrade/pull/652)
|
|
||||||
> that you can refer to.
|
|
||||||
|
|
||||||
1. bumps the version number.
|
1. bumps the version number.
|
||||||
|
|
||||||
> If there are breaking changes, the major version number should be increased.
|
> If there are breaking changes, the major version number should be increased.
|
||||||
|
|
||||||
2. If the major versioin number gets bumped, update [SECURITY.md][SECURITY_file_link].
|
2. If the major versioin number gets bumped, update [SECURITY.md][SECURITY_file_link].
|
||||||
|
|
||||||
[SECURITY_file_link]: https://github.com/topgrade-rs/topgrade/blob/main/SECURITY.md
|
[SECURITY_file_link]: https://github.com/topgrade-rs/topgrade/blob/main/SECURITY.md
|
||||||
|
|
||||||
3. Overwrite [`BREAKINGCHANGES`][breaking_changes] with
|
3. Overwrite [`BREAKINGCHANGES`][breaking_changes] with
|
||||||
[`BREAKINGCHANGES_dev`][breaking_changes_dev], and create a new dev file:
|
[`BREAKINGCHANGES_dev`][breaking_changes_dev], and create a new dev file:
|
||||||
|
|
||||||
```sh'
|
```sh'
|
||||||
@@ -24,46 +19,3 @@
|
|||||||
|
|
||||||
[breaking_changes_dev]: https://github.com/topgrade-rs/topgrade/blob/main/BREAKINGCHANGES_dev.md
|
[breaking_changes_dev]: https://github.com/topgrade-rs/topgrade/blob/main/BREAKINGCHANGES_dev.md
|
||||||
[breaking_changes]: https://github.com/topgrade-rs/topgrade/blob/main/BREAKINGCHANGES.md
|
[breaking_changes]: https://github.com/topgrade-rs/topgrade/blob/main/BREAKINGCHANGES.md
|
||||||
|
|
||||||
2. Check and merge that PR.
|
|
||||||
|
|
||||||
3. Go to the [release](https://github.com/topgrade-rs/topgrade/releases) page
|
|
||||||
and click the [Draft a new release button](https://github.com/topgrade-rs/topgrade/releases/new)
|
|
||||||
|
|
||||||
4. Write the release notes
|
|
||||||
|
|
||||||
We usually use GitHub's [Automatically generated release notes][auto_gen_release_notes]
|
|
||||||
functionality to generate release notes, but you write your own one instead.
|
|
||||||
|
|
||||||
[auto_gen_release_notes]: https://docs.github.com/en/repositories/releasing-projects-on-github/automatically-generated-release-notes
|
|
||||||
|
|
||||||
5. Attaching binaries
|
|
||||||
|
|
||||||
You don't need to do this as our CI will automatically do it for you,
|
|
||||||
binaries for Linux, macOS and Windows will be created and attached.
|
|
||||||
|
|
||||||
And the CI will publish the new binary to:
|
|
||||||
|
|
||||||
1. AUR
|
|
||||||
2. PyPi
|
|
||||||
3. Homebrew (seems that this is not working correctly)
|
|
||||||
4. Winget
|
|
||||||
|
|
||||||
6. Manually release it to Crates.io
|
|
||||||
|
|
||||||
> Yeah, this is unfortunate, our CI won't do this for us. We should probably add one.
|
|
||||||
|
|
||||||
1. `cd` to the Topgrade directory, make sure that it is the latest version
|
|
||||||
(i.e., including the PR that bumps the version number).
|
|
||||||
2. Set up your token with `cargo login`.
|
|
||||||
3. Dry-run the publish `cargo publish --dry-run`.
|
|
||||||
4. If step 3 works, then do the final release `cargo publish`.
|
|
||||||
|
|
||||||
> You can also take a look at the official tutorial [Publishing on crates.io][doc]
|
|
||||||
>
|
|
||||||
> [doc]: https://doc.rust-lang.org/cargo/reference/publishing.html
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -8,4 +8,3 @@ We only support the latest major version and each subversion.
|
|||||||
| -------- | ------------------ |
|
| -------- | ------------------ |
|
||||||
| 16.0.x | :white_check_mark: |
|
| 16.0.x | :white_check_mark: |
|
||||||
| < 16.0 | :x: |
|
| < 16.0 | :x: |
|
||||||
|
|
||||||
|
|||||||
35
build-all.sh
35
build-all.sh
@@ -1,4 +1,5 @@
|
|||||||
#!/usr/bin/env sh
|
#!/usr/bin/env bash
|
||||||
|
|
||||||
build_function() {
|
build_function() {
|
||||||
rustup update
|
rustup update
|
||||||
cargo install cross
|
cargo install cross
|
||||||
@@ -20,7 +21,7 @@ build_function() {
|
|||||||
|
|
||||||
package_function() {
|
package_function() {
|
||||||
|
|
||||||
cd build
|
cd build || exit 1
|
||||||
mkdir x86_64-unknown-linux-gnu/
|
mkdir x86_64-unknown-linux-gnu/
|
||||||
mkdir x86_64-unknown-linux-musl/
|
mkdir x86_64-unknown-linux-musl/
|
||||||
mkdir x86_64-unknown-freebsd/
|
mkdir x86_64-unknown-freebsd/
|
||||||
@@ -35,28 +36,28 @@ package_function() {
|
|||||||
cp ../target/aarch64-unknown-linux-musl/release/topgrade aarch64-unknown-linux-musl/topgrade
|
cp ../target/aarch64-unknown-linux-musl/release/topgrade aarch64-unknown-linux-musl/topgrade
|
||||||
cp ../target/x86_64-pc-windows-gnu/release/topgrade.exe x86_64-pc-windows-gnu/topgrade.exe
|
cp ../target/x86_64-pc-windows-gnu/release/topgrade.exe x86_64-pc-windows-gnu/topgrade.exe
|
||||||
|
|
||||||
cd x86_64-unknown-linux-gnu/
|
cd x86_64-unknown-linux-gnu/ || exit 1
|
||||||
tar -czf ../topgrade-${ans}-x86_64-linux-gnu.tar.gz topgrade
|
tar -czf "../topgrade-${ans}-x86_64-linux-gnu.tar.gz" topgrade
|
||||||
cd ..
|
cd ..
|
||||||
|
|
||||||
cd x86_64-unknown-linux-musl
|
cd x86_64-unknown-linux-musl/ || exit 1
|
||||||
tar -czf ../topgrade-${ans}-x86_64-linux-musl.tar.gz topgrade
|
tar -czf "../topgrade-${ans}-x86_64-linux-musl.tar.gz" topgrade
|
||||||
cd ..
|
cd ..
|
||||||
|
|
||||||
cd x86_64-unknown-freebsd/
|
cd x86_64-unknown-freebsd/ || exit 1
|
||||||
tar -czf ../topgrade-${ans}-x86_64-freebsd.tar.gz topgrade
|
tar -czf "../topgrade-${ans}-x86_64-freebsd.tar.gz" topgrade
|
||||||
cd ..
|
cd ..
|
||||||
|
|
||||||
cd aarch64-unknown-linux-gnu/
|
cd aarch64-unknown-linux-gnu/ || exit 1
|
||||||
tar -czf ../topgrade-${ans}-aarch64-linux-gnu.tar.gz topgrade
|
tar -czf "../topgrade-${ans}-aarch64-linux-gnu.tar.gz" topgrade
|
||||||
cd ..
|
cd ..
|
||||||
|
|
||||||
cd aarch64-unknown-linux-musl/
|
cd aarch64-unknown-linux-musl/ || exit 1
|
||||||
tar -czf ../topgrade-${ans}-aarch64-linux-musl.tar.gz topgrade
|
tar -czf "../topgrade-${ans}-aarch64-linux-musl.tar.gz" topgrade
|
||||||
cd ..
|
cd ..
|
||||||
|
|
||||||
cd x86_64-pc-windows-gnu/
|
cd x86_64-pc-windows-gnu/ || exit 1
|
||||||
zip -q ../topgrade-${ans}-x86_64-windows.zip topgrade.exe
|
zip -q "../topgrade-${ans}-x86_64-windows.zip" topgrade.exe
|
||||||
cd ..
|
cd ..
|
||||||
cd ..
|
cd ..
|
||||||
|
|
||||||
@@ -65,17 +66,19 @@ package_function() {
|
|||||||
print_checksums() {
|
print_checksums() {
|
||||||
|
|
||||||
|
|
||||||
cd build/
|
cd build/ || exit 1
|
||||||
sha256sum topgrade-${ans}-*
|
sha256sum topgrade-"${ans}"-*
|
||||||
cd ../
|
cd ../
|
||||||
}
|
}
|
||||||
|
|
||||||
while true; do
|
while true; do
|
||||||
|
|
||||||
echo "You should always have a look on scripts you download from the internet."
|
echo "You should always have a look on scripts you download from the internet."
|
||||||
|
# shellcheck disable=SC2162
|
||||||
read -p "Do you still want to proceed? (y/n) " yn
|
read -p "Do you still want to proceed? (y/n) " yn
|
||||||
|
|
||||||
echo -n "Input version number: "
|
echo -n "Input version number: "
|
||||||
|
# shellcheck disable=SC2162
|
||||||
read ans
|
read ans
|
||||||
mkdir build
|
mkdir build
|
||||||
|
|
||||||
|
|||||||
@@ -6,6 +6,13 @@
|
|||||||
|
|
||||||
|
|
||||||
[misc]
|
[misc]
|
||||||
|
# On Unix systems, Topgrade should not be run as root, it
|
||||||
|
# will run commands with sudo or equivalent where needed.
|
||||||
|
# Set this to true to suppress the warning and confirmation
|
||||||
|
# prompt if Topgrade detects it is being run as root.
|
||||||
|
# (default: false)
|
||||||
|
# allow_root = false
|
||||||
|
|
||||||
# Run `sudo -v` to cache credentials at the start of the run
|
# Run `sudo -v` to cache credentials at the start of the run
|
||||||
# This avoids a blocking password prompt in the middle of an unattended run
|
# This avoids a blocking password prompt in the middle of an unattended run
|
||||||
# (default: false)
|
# (default: false)
|
||||||
@@ -44,6 +51,10 @@
|
|||||||
# Do not ask to retry failed steps (default: false)
|
# Do not ask to retry failed steps (default: false)
|
||||||
# no_retry = true
|
# no_retry = true
|
||||||
|
|
||||||
|
# Show the reason for skipped steps (default: false)
|
||||||
|
# This has no effect if the "only" option is specified
|
||||||
|
# show_skipped = true
|
||||||
|
|
||||||
# Run inside tmux (default: false)
|
# Run inside tmux (default: false)
|
||||||
# run_in_tmux = true
|
# run_in_tmux = true
|
||||||
|
|
||||||
@@ -111,6 +122,19 @@
|
|||||||
# poetry_force_self_update = true
|
# poetry_force_self_update = true
|
||||||
|
|
||||||
|
|
||||||
|
[conda]
|
||||||
|
# Additional named conda environments to update (`conda env update -n env_name`)
|
||||||
|
# env_names = [
|
||||||
|
# "Toolbox",
|
||||||
|
# "PyTorch"
|
||||||
|
# ]
|
||||||
|
# Additional conda environment paths to update (`conda env update -p env_path`)
|
||||||
|
# env_paths = [
|
||||||
|
# "~/webserver/.conda/",
|
||||||
|
# "~/experiments/.conda/"
|
||||||
|
# ]
|
||||||
|
|
||||||
|
|
||||||
[composer]
|
[composer]
|
||||||
# self_update = true
|
# self_update = true
|
||||||
|
|
||||||
@@ -180,7 +204,7 @@
|
|||||||
# rpm_ostree = false
|
# rpm_ostree = false
|
||||||
|
|
||||||
# For Fedora/CentOS/RHEL Atomic variants, if `bootc` is available and this configuration entry is set to true, use
|
# For Fedora/CentOS/RHEL Atomic variants, if `bootc` is available and this configuration entry is set to true, use
|
||||||
# it to do the update - Will also supercede rpm-ostree if enabled
|
# it to do the update - Will also supersede rpm-ostree if enabled
|
||||||
# (default: false)
|
# (default: false)
|
||||||
# bootc = false
|
# bootc = false
|
||||||
|
|
||||||
@@ -192,6 +216,13 @@
|
|||||||
# home_manager_arguments = ["--flake", "file"]
|
# home_manager_arguments = ["--flake", "file"]
|
||||||
|
|
||||||
|
|
||||||
|
[mandb]
|
||||||
|
# Enable the mandb step (to update manual entries).
|
||||||
|
# Mandb is updated in the background by a service on most systems by default.
|
||||||
|
# (default: false)
|
||||||
|
# enable = true
|
||||||
|
|
||||||
|
|
||||||
[git]
|
[git]
|
||||||
# How many repos to pull at max in parallel
|
# How many repos to pull at max in parallel
|
||||||
# max_concurrency = 5
|
# max_concurrency = 5
|
||||||
@@ -213,13 +244,17 @@
|
|||||||
# Manually select Windows updates
|
# Manually select Windows updates
|
||||||
# accept_all_updates = false
|
# accept_all_updates = false
|
||||||
|
|
||||||
|
# Controls whether to automatically reboot the computer when updates are
|
||||||
|
# installed that request it. (default: "no", allowed values: "yes", "no", "ask")
|
||||||
|
# updates_auto_reboot = "yes"
|
||||||
|
|
||||||
# open_remotes_in_new_terminal = true
|
# open_remotes_in_new_terminal = true
|
||||||
|
|
||||||
# wsl_update_pre_release = true
|
# wsl_update_pre_release = true
|
||||||
|
|
||||||
# wsl_update_use_web_download = true
|
# wsl_update_use_web_download = true
|
||||||
|
|
||||||
# The default for winget_install_silently is true,
|
# The default for winget_install_silently is true,
|
||||||
# this example turns off silent install.
|
# this example turns off silent install.
|
||||||
# winget_install_silently = false
|
# winget_install_silently = false
|
||||||
|
|
||||||
@@ -228,6 +263,16 @@
|
|||||||
# manager such as Scoop or Cargo
|
# manager such as Scoop or Cargo
|
||||||
# self_rename = true
|
# self_rename = true
|
||||||
|
|
||||||
|
# Use sudo to elevate privileges for the Windows Package Manager (winget)
|
||||||
|
# Only use this option if you want to run the Winget step in sudo-mode.
|
||||||
|
# Running winget in sudo-mode is generally not recommended, as not every
|
||||||
|
# package supports installing / upgrading in sudo-mode and it may cause issues
|
||||||
|
# with some packages or may even cause the Winget-step to fail.
|
||||||
|
# If any problems occur, please try running Topgrade without this option first
|
||||||
|
# before reporting an issue.
|
||||||
|
# (default: false)
|
||||||
|
# winget_use_sudo = true
|
||||||
|
|
||||||
|
|
||||||
[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
|
||||||
@@ -281,7 +326,7 @@
|
|||||||
# runtime = "podman"
|
# runtime = "podman"
|
||||||
|
|
||||||
[lensfun]
|
[lensfun]
|
||||||
# If disabled, Topgrade invokes `lensfun‑update‑data` without root priviledge,
|
# If disabled, Topgrade invokes `lensfun‑update‑data` without root privilege,
|
||||||
# then the update will be only available to you. Otherwise, `sudo` is required,
|
# then the update will be only available to you. Otherwise, `sudo` is required,
|
||||||
# and the update will be installed system-wide, i.e., available to all users.
|
# and the update will be installed system-wide, i.e., available to all users.
|
||||||
# (default: false)
|
# (default: false)
|
||||||
@@ -325,3 +370,9 @@
|
|||||||
# extensions should be updated for.
|
# extensions should be updated for.
|
||||||
# (default: this won't be set by default)
|
# (default: this won't be set by default)
|
||||||
# profile = ""
|
# profile = ""
|
||||||
|
|
||||||
|
[pixi]
|
||||||
|
# Show the release notes of the latest pixi release
|
||||||
|
# during the pixi step
|
||||||
|
# (default: false)
|
||||||
|
# include_release_notes = false
|
||||||
|
|||||||
292
locales/app.yml
292
locales/app.yml
@@ -80,14 +80,14 @@ _version: 2
|
|||||||
zh_CN: "Topgrade 已在新的 tmux 会话中启动"
|
zh_CN: "Topgrade 已在新的 tmux 会话中启动"
|
||||||
zh_TW: "Topgrade 已啟動新 tmux 程序"
|
zh_TW: "Topgrade 已啟動新 tmux 程序"
|
||||||
de: "Topgrade in einer neuen tmux-Sitzung gestartet"
|
de: "Topgrade in einer neuen tmux-Sitzung gestartet"
|
||||||
'Topgrade upgraded to {version}:\n':
|
"Topgrade upgraded to {version}:\n":
|
||||||
en: 'Topgrade upgraded to %{version}:\n'
|
en: "Topgrade upgraded to %{version}:\n"
|
||||||
lt: "Topgrade atnaujintas iki %{version}:\n"
|
lt: "Topgrade atnaujintas iki %{version}:\n"
|
||||||
es: 'Topgrade actualizado a %{version}:\n'
|
es: "Topgrade actualizado a %{version}:\n"
|
||||||
fr: 'Topgrade mis à jour vers %{version}:\n'
|
fr: "Topgrade mis à jour vers %{version}:\n"
|
||||||
zh_CN: '已将 Topgrade 更新至 %{version}: \n'
|
zh_CN: "已将 Topgrade 更新至 %{version}: \n"
|
||||||
zh_TW: '已將 Topgrade 更新至 %{version}:\n'
|
zh_TW: "已將 Topgrade 更新至 %{version}:\n"
|
||||||
de: 'Topgrade auf Version %{version} aktualisiert:\n'
|
de: "Topgrade auf Version %{version} aktualisiert:\n"
|
||||||
"Topgrade is up-to-date":
|
"Topgrade is up-to-date":
|
||||||
en: "Topgrade is up-to-date"
|
en: "Topgrade is up-to-date"
|
||||||
lt: "Topgrade yra naujausia"
|
lt: "Topgrade yra naujausia"
|
||||||
@@ -214,14 +214,6 @@ _version: 2
|
|||||||
zh_CN: "正在跳过"
|
zh_CN: "正在跳过"
|
||||||
zh_TW: "正在略過"
|
zh_TW: "正在略過"
|
||||||
de: "Überspringe"
|
de: "Überspringe"
|
||||||
"Aura(<0.4.6) requires sudo installed to work with AUR packages":
|
|
||||||
en: "Aura(<0.4.6) requires sudo installed to work with AUR packages"
|
|
||||||
lt: "Aura (<0.4.6) reikalauja sudo įdiegimo, kad galėtų naudoti AUR paketus"
|
|
||||||
es: "Aura(<0.4.6) requiere tener sudo instalado para funcionar con paquetes AUR"
|
|
||||||
fr: "Aura(<0.4.6) nécessite sudo pour fonctionner avec les paquets AUR"
|
|
||||||
zh_CN: "Aura(<0.4.6) 依赖 sudo 安装 AUR 软件包。"
|
|
||||||
zh_TW: "Aura(<0.4.6)依賴 sudo 安裝 AUR 套件"
|
|
||||||
de: "Aura(<0.4.6) benötigt sudo zur Verwendung von AUR-Paketen"
|
|
||||||
"Pacman backup configuration files found:":
|
"Pacman backup configuration files found:":
|
||||||
en: "Pacman backup configuration files found:"
|
en: "Pacman backup configuration files found:"
|
||||||
lt: "Rasti Pacman atsarginės konfigūracijos failai:"
|
lt: "Rasti Pacman atsarginės konfigūracijos failai:"
|
||||||
@@ -414,6 +406,14 @@ _version: 2
|
|||||||
zh_CN: "在 $PATH 中找不到 %{binary_name} 二进制"
|
zh_CN: "在 $PATH 中找不到 %{binary_name} 二进制"
|
||||||
zh_TW: "在 $PATH 中找不到 %{binary_name} 執行檔"
|
zh_TW: "在 $PATH 中找不到 %{binary_name} 執行檔"
|
||||||
de: "Kann %{binary_name} nicht im PATH finden"
|
de: "Kann %{binary_name} nicht im PATH finden"
|
||||||
|
"Cannot find any of {binary_names} in PATH":
|
||||||
|
en: "Cannot find any of %{binary_names} in PATH"
|
||||||
|
lt: "Nepavyksta rasti jokių %{binary_names} PATH sąraše"
|
||||||
|
es: "No se puede encontrar ninguno de %{binary_names} en PATH"
|
||||||
|
fr: "Impossible de trouver l'un des %{binary_names} dans le PATH"
|
||||||
|
zh_CH: "在 PATH 中找不到 %{binary_names}"
|
||||||
|
zh_TW: "在 PATH 中找不到 %{binary_names}"
|
||||||
|
de: "Kann keines von %{binary_names} im PATH finden"
|
||||||
"Failed to get a UTF-8 encoded hostname":
|
"Failed to get a UTF-8 encoded hostname":
|
||||||
en: "Failed to get a UTF-8 encoded hostname"
|
en: "Failed to get a UTF-8 encoded hostname"
|
||||||
lt: "Nepavyko gauti UTF-8 koduoto kompiuterio pavadinimo"
|
lt: "Nepavyko gauti UTF-8 koduoto kompiuterio pavadinimo"
|
||||||
@@ -654,29 +654,29 @@ _version: 2
|
|||||||
zh_CN: "无法使用 `fish_update_completions`"
|
zh_CN: "无法使用 `fish_update_completions`"
|
||||||
zh_TW: "無法使用 `fish_update_completions`"
|
zh_TW: "無法使用 `fish_update_completions`"
|
||||||
de: "`fish_update_completions` ist nicht verfügbar"
|
de: "`fish_update_completions` ist nicht verfügbar"
|
||||||
"Desktop doest not appear to be gnome":
|
"Desktop does not appear to be GNOME":
|
||||||
en: "Desktop doest not appear to be gnome"
|
en: "Desktop does not appear to be GNOME"
|
||||||
lt: "Darbalaukis, matyt, nėra Gnome"
|
lt: "Darbalaukis, matyt, nėra GNOME"
|
||||||
es: "El escritorio no parece ser Gnome"
|
es: "El escritorio no parece ser GNOME"
|
||||||
fr: "Le bureau ne semble pas être Gnome"
|
fr: "Le bureau ne semble pas être GNOME"
|
||||||
zh_CN: "桌面环境不是 Gnome"
|
zh_CN: "桌面环境不是 GNOME"
|
||||||
zh_TW: "桌面環境不是 Gnome"
|
zh_TW: "桌面環境不是 GNOME"
|
||||||
de: "Desktop scheint nicht GNOME zu sein"
|
de: "Desktop scheint nicht GNOME zu sein"
|
||||||
"Gnome shell extensions are unregistered in DBus":
|
"GNOME shell extensions are unregistered in DBus":
|
||||||
en: "Gnome shell extensions are unregistered in DBus"
|
en: "GNOME shell extensions are unregistered in DBus"
|
||||||
lt: "Gnome Shell priedai nėra užregistruoti DBus'e"
|
lt: "GNOME Shell priedai nėra užregistruoti DBus'e"
|
||||||
es: "Las extensiones de Gnome Shell no están registradas en DBus"
|
es: "Las extensiones de GNOME Shell no están registradas en DBus"
|
||||||
fr: "Les extensions de Gnome Shell ne sont pas enregistrées dans DBus"
|
fr: "Les extensions de GNOME Shell ne sont pas enregistrées dans DBus"
|
||||||
zh_CN: "Gnome Shell 扩展在 DBus中未被注册"
|
zh_CN: "GNOME Shell 扩展在 DBus中未被注册"
|
||||||
zh_TW: "Gnome Shell 擴充功能在 DBus 中未被註冊"
|
zh_TW: "GNOME Shell 擴充功能在 DBus 中未被註冊"
|
||||||
de: "GNOME-Shell-Erweiterungen sind im DBus nicht registriert"
|
de: "GNOME-Shell-Erweiterungen sind im DBus nicht registriert"
|
||||||
"Gnome Shell extensions":
|
"GNOME Shell extensions":
|
||||||
en: "Gnome Shell extensions"
|
en: "GNOME Shell extensions"
|
||||||
lt: "Gnome Shell priedai"
|
lt: "GNOME Shell priedai"
|
||||||
es: "Extensiones de Gnome Shell"
|
es: "Extensiones de GNOME Shell"
|
||||||
fr: "Extensions de Gnome Shell"
|
fr: "Extensions de GNOME Shell"
|
||||||
zh_CN: "Gnome Shell 扩展"
|
zh_CN: "GNOME Shell 扩展"
|
||||||
zh_TW: "Gnome Shell 擴充功能"
|
zh_TW: "GNOME Shell 擴充功能"
|
||||||
de: "GNOME-Shell-Erweiterungen"
|
de: "GNOME-Shell-Erweiterungen"
|
||||||
"Not a custom brew for macOS":
|
"Not a custom brew for macOS":
|
||||||
en: "Not a custom brew for macOS"
|
en: "Not a custom brew for macOS"
|
||||||
@@ -774,22 +774,22 @@ _version: 2
|
|||||||
zh_CN: "无法找到安装在 WSL 中的 Topgrade"
|
zh_CN: "无法找到安装在 WSL 中的 Topgrade"
|
||||||
zh_TW: "尚未在 WSL 內安裝 Topgrade"
|
zh_TW: "尚未在 WSL 內安裝 Topgrade"
|
||||||
de: "Konnte Topgrade nicht in WSL finden"
|
de: "Konnte Topgrade nicht in WSL finden"
|
||||||
"Consider installing PSWindowsUpdate as the use of Windows Update via USOClient is not supported.":
|
"The PSWindowsUpdate PowerShell module isn't installed so Topgrade can't run Windows Update.\nInstall PSWindowsUpdate by running `Install-Module PSWindowsUpdate` in PowerShell.":
|
||||||
en: "Consider installing PSWindowsUpdate as the use of Windows Update via USOClient is not supported."
|
en: "The PSWindowsUpdate PowerShell module isn't installed so Topgrade can't run Windows Update.\nInstall PSWindowsUpdate by running `Install-Module PSWindowsUpdate` in PowerShell."
|
||||||
lt: "Apsvarstykite PSWindowsUpdate įdiegimą, nes Windows Update per USOClient nepalaikomas."
|
lt: "PowerShell modulis PSWindowsUpdate nėra įdiegtas, todėl Topgrade negali paleisti „Windows Update“.\nĮdiekite PSWindowsUpdate paleisdami `Install-Module PSWindowsUpdate` PowerShell aplinkoje."
|
||||||
es: "Considere instalar PSWindowsUpdate ya que no se admite el uso de Windows Update a través de USOClient."
|
es: "El módulo de PowerShell PSWindowsUpdate no está instalado, por lo que Topgrade no puede ejecutar Windows Update.\nInstala PSWindowsUpdate ejecutando `Install-Module PSWindowsUpdate` en PowerShell."
|
||||||
fr: "Envisagez d'installer PSWindowsUpdate car l'utilisation de Windows Update via USOClient n'est pas prise en charge."
|
fr: "Le module PowerShell PSWindowsUpdate n’est pas installé, donc Topgrade ne peut pas exécuter Windows Update.\nInstallez PSWindowsUpdate en exécutant `Install-Module PSWindowsUpdate` dans PowerShell."
|
||||||
zh_CN: "目前不支持使用 USOClient 管理 Windows 更新。建议安装 PSWindowsUpdate。"
|
zh_CN: "未安装 PowerShell 模块 PSWindowsUpdate,因此 Topgrade 无法运行 Windows 更新。\n请在 PowerShell 中运行 `Install-Module PSWindowsUpdate` 来安装 PSWindowsUpdate。"
|
||||||
zh_TW: "目前不支援使用 USOClient 管理 Windows 更新。建議安裝 PSWindowsUpdate。"
|
zh_TW: "PowerShell 模組 PSWindowsUpdate 未安裝,因此 Topgrade 無法執行 Windows 更新。\n請在 PowerShell 中執行 `Install-Module PSWindowsUpdate` 來安裝 PSWindowsUpdate。"
|
||||||
de: "Erwägen Sie die Installation von PSWindowsUpdate, da die Verwendung von Windows Update über USOClient nicht unterstützt wird."
|
de: "Das PowerShell-Modul PSWindowsUpdate ist nicht installiert, daher kann Topgrade Windows Update nicht ausführen.\nInstallieren Sie PSWindowsUpdate, indem Sie `Install-Module PSWindowsUpdate` in PowerShell ausführen."
|
||||||
"USOClient not supported.":
|
"PSWindowsUpdate is not installed":
|
||||||
en: "USOClient not supported."
|
en: "PSWindowsUpdate is not installed"
|
||||||
lt: "USOClient nepalaikomas."
|
lt: "PSWindowsUpdate nėra įdiegtas"
|
||||||
es: "USOClient no es admitido."
|
es: "PSWindowsUpdate no está instalado"
|
||||||
fr: "USOClient n'est pas pris en charge."
|
fr: "PSWindowsUpdate n'est pas installé"
|
||||||
zh_CN: "不支持 USOClient"
|
zh_CN: "未安装 PSWindowsUpdate"
|
||||||
zh_TW: "不支援 USOClient。"
|
zh_TW: "未安裝 PSWindowsUpdate"
|
||||||
de: "USOClient wird nicht unterstützt."
|
de: "PSWindowsUpdate ist nicht installiert"
|
||||||
"Connecting to {hostname}...":
|
"Connecting to {hostname}...":
|
||||||
en: "Connecting to %{hostname}..."
|
en: "Connecting to %{hostname}..."
|
||||||
lt: "Jungiamasi prie %{hostname}..."
|
lt: "Jungiamasi prie %{hostname}..."
|
||||||
@@ -1109,25 +1109,123 @@ _version: 2
|
|||||||
fr: "Réessayer ? (y) Oui / (N) Non / (s) Shell / (q) Quitter"
|
fr: "Réessayer ? (y) Oui / (N) Non / (s) Shell / (q) Quitter"
|
||||||
zh_CN: "再试一次?(y)是/(N)否/(s)Shell/(q)退出"
|
zh_CN: "再试一次?(y)是/(N)否/(s)Shell/(q)退出"
|
||||||
zh_TW: "再試一次? (y)是/(N)否/(s)殼層/(q)退出"
|
zh_TW: "再試一次? (y)是/(N)否/(s)殼層/(q)退出"
|
||||||
de: "Wiederholen? (y)a/(N)ein/(s)hell/(q)uit"
|
de: "Wiederholen? (y) Ja / (n) Nein / (s) Shell / (q) Beenden"
|
||||||
|
|
||||||
# 'R', 'S', 'Q' have to stay the same throughout all translations. Eg German would look like "\n(R) Neustarten\n(S) Konsole\n(Q) Beenden"
|
# 'R', 'S', 'Q' have to stay the same throughout all translations. Eg German would look like "\n(R) Neustarten\n(S) Konsole\n(Q) Beenden"
|
||||||
'\n(R)eboot\n(S)hell\n(Q)uit':
|
"\n(R)eboot\n(S)hell\n(Q)uit":
|
||||||
en: '\n(R)eboot\n(S)hell\n(Q)uit'
|
en: "\n(R)eboot\n(S)hell\n(Q)uit"
|
||||||
lt: "\n(R)perkrovimas\n(S)shell\n(Q)išeiti"
|
lt: "\n(R)perkrovimas\n(S)shell\n(Q)išeiti"
|
||||||
es: "\n(R) Reiniciar\n(S) Shell\n(Q) Salir"
|
es: "\n(R) Reiniciar\n(S) Shell\n(Q) Salir"
|
||||||
fr: '\n(R) Redémarrer\n(S) Shell\n(Q) Quitter'
|
fr: "\n(R) Redémarrer\n(S) Shell\n(Q) Quitter"
|
||||||
zh_CN: '\n(R)重启\n(S)Shell\n(Q)退出'
|
zh_CN: "\n(R)重启\n(S)Shell\n(Q)退出"
|
||||||
zh_TW: '\n(R)重新啟動\n(S)殼層\n(Q)退出'
|
zh_TW: "\n(R)重新啟動\n(S)殼層\n(Q)退出"
|
||||||
de: '\n(R) Neustarten\n(S)hell\n(Q)uit beenden'
|
de: "\n(R) Neustarten\n(S)hell\n(Q)uit beenden"
|
||||||
"Require sudo or counterpart but not found, skip":
|
|
||||||
en: "Require sudo or counterpart but not found, skip"
|
"Continue?":
|
||||||
lt: "Reikalingas sudo arba atitikmuo, bet nerasta, praleidžiama"
|
en: "Continue?"
|
||||||
es: "Se requiere sudo o su equivalente pero no ha sido encontrado, omitiendo"
|
lt: "Tęsti?"
|
||||||
fr: "Nécessite sudo ou un équivalent mais n'a pas été trouvé, passé"
|
es: "¿Continuar?"
|
||||||
zh_CN: "找不到权限管理程序(sudo 等),跳过"
|
fr: "Continuer ?"
|
||||||
zh_TW: "找不到權限管理程式(sudo 等),略過"
|
zh_CN: "继续?"
|
||||||
de: "Benötigt sudo oder Äquivalent, aber nicht gefunden, überspringe"
|
zh_TW: "繼續?"
|
||||||
|
de: "Fortfahren?"
|
||||||
|
|
||||||
|
"Topgrade should not be run as root, it will run commands with sudo or equivalent where needed.":
|
||||||
|
en: "Topgrade should not be run as root, it will run commands with sudo or equivalent where needed."
|
||||||
|
lt: "Topgrade neturėtų būti paleistas kaip root, jis vykdys komandas su sudo ar atitikmeniu, kai to reikės."
|
||||||
|
es: "Topgrade no debe ejecutarse como root, ejecutará comandos con sudo o equivalente cuando sea necesario."
|
||||||
|
fr: "Topgrade ne doit pas être exécuté en tant que root, il exécutera les commandes avec sudo ou équivalent si nécessaire."
|
||||||
|
zh_CN: "Topgrade 不应以 root 身份运行,它会在需要时使用 sudo 或等效工具执行命令。"
|
||||||
|
zh_TW: "Topgrade 不應以 root 身份執行,它會在需要時使用 sudo 或等效工具執行命令。"
|
||||||
|
de: "Topgrade sollte nicht als Root ausgeführt werden, es führt Befehle mit sudo oder einem Äquivalent aus, wenn erforderlich."
|
||||||
|
"Could not find sudo":
|
||||||
|
en: "Could not find sudo"
|
||||||
|
lt: "Nepavyko rasti sudo"
|
||||||
|
es: "No se pudo encontrar sudo"
|
||||||
|
fr: "Impossible de trouver sudo"
|
||||||
|
zh_CN: "未找到 sudo"
|
||||||
|
zh_TW: "找不到 sudo"
|
||||||
|
de: "Konnte sudo nicht finden"
|
||||||
|
"Skipping step, sudo is required":
|
||||||
|
en: "Skipping step, sudo is required"
|
||||||
|
lt: "Žingsnis praleidžiamas, reikalingas sudo"
|
||||||
|
es: "Omitiendo paso, se requiere sudo"
|
||||||
|
fr: "Étape ignorée, sudo est requis"
|
||||||
|
zh_CN: "跳过步骤,需要 sudo"
|
||||||
|
zh_TW: "跳過步驟,需要 sudo"
|
||||||
|
de: "Schritt wird übersprungen, sudo ist erforderlich"
|
||||||
|
"\nSome steps were skipped as sudo or equivalent could not be found.":
|
||||||
|
en: "\nSome steps were skipped as sudo or equivalent could not be found."
|
||||||
|
lt: "\nKai kurie veiksmai buvo praleisti, nes nepavyko rasti sudo ar atitikmens."
|
||||||
|
es: "\nAlgunos pasos se omitieron porque no se pudo encontrar sudo o equivalente."
|
||||||
|
fr: "\nCertaines étapes ont été ignorées car sudo ou équivalent est introuvable."
|
||||||
|
zh_CN: "\n由于未找到 sudo 或等效工具,某些步骤被跳过。"
|
||||||
|
zh_TW: "\n由於找不到 sudo 或等效工具,某些步驟已跳過。"
|
||||||
|
de: "\nEinige Schritte wurden übersprungen, da sudo oder ein Äquivalent nicht gefunden wurde."
|
||||||
|
"Install one of `sudo`, `doas`, `pkexec`, `run0` or `please` to run these steps.":
|
||||||
|
en: "Install one of `sudo`, `doas`, `pkexec`, `run0` or `please` to run these steps."
|
||||||
|
lt: "Įdiekite vieną iš `sudo`, `doas`, `pkexec`, `run0` arba `please`, kad vykdytumėte šiuos veiksmus."
|
||||||
|
es: "Instale uno de `sudo`, `doas`, `pkexec`, `run0` o `please` para ejecutar estos pasos."
|
||||||
|
fr: "Installez l’un de `sudo`, `doas`, `pkexec`, `run0` ou `please` pour exécuter ces étapes."
|
||||||
|
zh_CN: "请安装 `sudo`、`doas`、`pkexec`、`run0` 或 `please` 之一来运行这些步骤。"
|
||||||
|
zh_TW: "請安裝 `sudo`、`doas`、`pkexec`、`run0` 或 `please` 之一來執行這些步驟。"
|
||||||
|
de: "Installieren Sie `sudo`, `doas`, `pkexec`, `run0` oder `please`, um diese Schritte auszuführen."
|
||||||
|
"Install gsudo to run these steps.":
|
||||||
|
en: "Install gsudo to run these steps."
|
||||||
|
lt: "Įdiekite gsudo, kad vykdytumėte šiuos veiksmus."
|
||||||
|
es: "Instale gsudo para ejecutar estos pasos."
|
||||||
|
fr: "Installez gsudo pour exécuter ces étapes."
|
||||||
|
zh_CN: "请安装 gsudo 来运行这些步骤。"
|
||||||
|
zh_TW: "請安裝 gsudo 來執行這些步驟。"
|
||||||
|
de: "Installieren Sie gsudo, um diese Schritte auszuführen."
|
||||||
|
"Install gsudo or enable Windows Sudo to run these steps.\nFor Windows Sudo, the default 'In a new window' mode is not supported as it prevents Topgrade from waiting for commands to finish. Please configure it to use 'Inline' mode instead.\nGo to https://go.microsoft.com/fwlink/?linkid=2257346 to learn more.":
|
||||||
|
en: "Install gsudo or enable Windows Sudo to run these steps.\nFor Windows Sudo, the default 'In a new window' mode is not supported as it prevents Topgrade from waiting for commands to finish. Please configure it to use 'Inline' mode instead.\nGo to https://go.microsoft.com/fwlink/?linkid=2257346 to learn more."
|
||||||
|
lt: "Įdiekite gsudo arba įjunkite Windows Sudo, kad vykdytumėte šiuos veiksmus.\nWindows Sudo numatytasis „Naujo lango“ režimas nepalaikomas, nes jis neleidžia Topgrade laukti, kol komandos bus baigtos. Prašome nustatyti „Inline“ režimą.\nDaugiau sužinokite adresu https://go.microsoft.com/fwlink/?linkid=2257346."
|
||||||
|
es: "Instale gsudo o habilite Windows Sudo para ejecutar estos pasos.\nEn Windows Sudo, el modo predeterminado 'En una nueva ventana' no es compatible porque impide que Topgrade espere a que los comandos terminen. Por favor, configúrelo en modo 'Inline'.\nMás información en https://go.microsoft.com/fwlink/?linkid=2257346."
|
||||||
|
fr: "Installez gsudo ou activez Windows Sudo pour exécuter ces étapes.\nAvec Windows Sudo, le mode par défaut « Dans une nouvelle fenêtre » n’est pas pris en charge car il empêche Topgrade d’attendre la fin des commandes. Veuillez le configurer en mode « Inline ».\nEn savoir plus sur https://go.microsoft.com/fwlink/?linkid=2257346."
|
||||||
|
zh_CN: "请安装 gsudo 或启用 Windows Sudo 来运行这些步骤。\n在 Windows Sudo 中,默认的“新窗口”模式不受支持,因为它会阻止 Topgrade 等待命令完成。请将其配置为“内联”模式。\n了解更多信息:https://go.microsoft.com/fwlink/?linkid=2257346"
|
||||||
|
zh_TW: "請安裝 gsudo 或啟用 Windows Sudo 來執行這些步驟。\n在 Windows Sudo 中,預設的「新視窗」模式不受支援,因為它會阻止 Topgrade 等待命令完成。請將其設定為「內嵌」模式。\n了解更多資訊:https://go.microsoft.com/fwlink/?linkid=2257346"
|
||||||
|
de: "Installieren Sie gsudo oder aktivieren Sie Windows Sudo, um diese Schritte auszuführen.\nFür Windows Sudo wird der Standardmodus „In einem neuen Fenster“ nicht unterstützt, da er verhindert, dass Topgrade auf den Abschluss der Befehle wartet. Bitte konfigurieren Sie es stattdessen auf „Inline“-Modus.\nMehr erfahren unter https://go.microsoft.com/fwlink/?linkid=2257346."
|
||||||
|
"Windows Sudo was found, but it is set to 'In a new window' mode, which prevents Topgrade from waiting for commands to finish. Please configure it to use 'Inline' mode instead.\nGo to https://go.microsoft.com/fwlink/?linkid=2257346 to learn more.":
|
||||||
|
en: "Windows Sudo was found, but it is set to 'In a new window' mode, which prevents Topgrade from waiting for commands to finish. Please configure it to use 'Inline' mode instead.\nGo to https://go.microsoft.com/fwlink/?linkid=2257346 to learn more."
|
||||||
|
lt: "Rastas Windows Sudo, bet jis nustatytas „Naujo lango“ režimu, kuris neleidžia Topgrade laukti, kol bus baigtos komandos. Prašome nustatyti „Inline“ režimą.\nDaugiau sužinokite adresu https://go.microsoft.com/fwlink/?linkid=2257346."
|
||||||
|
es: "Se encontró Windows Sudo, pero está configurado en el modo 'En una nueva ventana', lo que impide que Topgrade espere a que los comandos finalicen. Por favor, configúrelo en modo 'Inline'.\nMás información en https://go.microsoft.com/fwlink/?linkid=2257346."
|
||||||
|
fr: "Windows Sudo a été trouvé, mais il est configuré en mode « Dans une nouvelle fenêtre », ce qui empêche Topgrade d’attendre la fin des commandes. Veuillez le configurer en mode « Inline ».\nEn savoir plus sur https://go.microsoft.com/fwlink/?linkid=2257346."
|
||||||
|
zh_CN: "检测到 Windows Sudo,但其被设置为“新窗口”模式,这会阻止 Topgrade 等待命令完成。请将其配置为“内联”模式。\n了解更多信息:https://go.microsoft.com/fwlink/?linkid=2257346"
|
||||||
|
zh_TW: "偵測到 Windows Sudo,但它被設定為「新視窗」模式,這會阻止 Topgrade 等待命令完成。請將其設定為「內嵌」模式。\n了解更多資訊:https://go.microsoft.com/fwlink/?linkid=2257346"
|
||||||
|
de: "Windows Sudo wurde gefunden, aber es ist auf den Modus „In einem neuen Fenster“ eingestellt, wodurch Topgrade nicht auf den Abschluss der Befehle warten kann. Bitte konfigurieren Sie es stattdessen auf den „Inline“-Modus.\nMehr erfahren unter https://go.microsoft.com/fwlink/?linkid=2257346."
|
||||||
|
"Cannot find sudo binary":
|
||||||
|
en: "Cannot find sudo binary"
|
||||||
|
lt: "Nepavyko rasti sudo dvejetainio failo"
|
||||||
|
es: "No se puede encontrar el binario de sudo"
|
||||||
|
fr: "Impossible de trouver le binaire sudo"
|
||||||
|
zh_CN: "找不到 sudo 可执行文件"
|
||||||
|
zh_TW: "找不到 sudo 可執行檔"
|
||||||
|
de: "Kann die sudo-Binärdatei nicht finden"
|
||||||
|
"Found Windows Sudo, but it is disabled":
|
||||||
|
en: "Found Windows Sudo, but it is disabled"
|
||||||
|
lt: "Rastas Windows Sudo, bet jis išjungtas"
|
||||||
|
es: "Se encontró Windows Sudo, pero está deshabilitado"
|
||||||
|
fr: "Windows Sudo a été trouvé, mais il est désactivé"
|
||||||
|
zh_CN: "检测到 Windows Sudo,但已被禁用"
|
||||||
|
zh_TW: "偵測到 Windows Sudo,但已被停用"
|
||||||
|
de: "Windows Sudo gefunden, aber es ist deaktiviert"
|
||||||
|
"Found Windows Sudo, but it is using 'In a new window' mode":
|
||||||
|
en: "Found Windows Sudo, but it is using 'In a new window' mode"
|
||||||
|
lt: "Rastas Windows Sudo, bet jis naudoja „Naujo lango“ režimą"
|
||||||
|
es: "Se encontró Windows Sudo, pero está usando el modo 'En una nueva ventana'"
|
||||||
|
fr: "Windows Sudo a été trouvé, mais il utilise le mode « Dans une nouvelle fenêtre »"
|
||||||
|
zh_CN: "检测到 Windows Sudo,但其正在使用“新窗口”模式"
|
||||||
|
zh_TW: "偵測到 Windows Sudo,但它正在使用「新視窗」模式"
|
||||||
|
de: "Windows Sudo gefunden, aber es verwendet den Modus „In einem neuen Fenster“"
|
||||||
|
"{sudo_kind} does not support the {option} option":
|
||||||
|
en: "%{sudo_kind} does not support the %{option} option"
|
||||||
|
lt: "%{sudo_kind} nepalaiko parinkties %{option}"
|
||||||
|
es: "%{sudo_kind} no admite la opción %{option}"
|
||||||
|
fr: "%{sudo_kind} ne prend pas en charge l’option %{option}"
|
||||||
|
zh_CN: "%{sudo_kind} 不支持 %{option} 选项"
|
||||||
|
zh_TW: "%{sudo_kind} 不支援 %{option} 選項"
|
||||||
|
de: "%{sudo_kind} unterstützt die Option %{option} nicht"
|
||||||
"sudo as user '{user}'":
|
"sudo as user '{user}'":
|
||||||
en: "sudo as user '%{user}'"
|
en: "sudo as user '%{user}'"
|
||||||
lt: "sudo kaip vartotojas '%{user}'"
|
lt: "sudo kaip vartotojas '%{user}'"
|
||||||
@@ -1184,8 +1282,8 @@ _version: 2
|
|||||||
zh_CN: "正在重新生成"
|
zh_CN: "正在重新生成"
|
||||||
zh_TW: "正在重新生成..."
|
zh_TW: "正在重新生成..."
|
||||||
de: "Neustarten..."
|
de: "Neustarten..."
|
||||||
"Could not find Topgrade in any WSL disribution":
|
"Could not find Topgrade in any WSL distribution":
|
||||||
en: "Could not find Topgrade in any WSL disribution"
|
en: "Could not find Topgrade in any WSL distribution"
|
||||||
lt: "Nepavyko rasti Topgrade jokioje WSL distribucijoje"
|
lt: "Nepavyko rasti Topgrade jokioje WSL distribucijoje"
|
||||||
es: "No se pudo encontrar Topgrade en ninguna distribución WSL"
|
es: "No se pudo encontrar Topgrade en ninguna distribución WSL"
|
||||||
fr: "Impossible de trouver Topgrade installé dans WSL"
|
fr: "Impossible de trouver Topgrade installé dans WSL"
|
||||||
@@ -1248,14 +1346,6 @@ _version: 2
|
|||||||
zh_CN: "成功,Microsoft Store 应用正在后台更新"
|
zh_CN: "成功,Microsoft Store 应用正在后台更新"
|
||||||
zh_TW: "成功,Microsoft Store 應用程式正在後台更新"
|
zh_TW: "成功,Microsoft Store 應用程式正在後台更新"
|
||||||
de: "Erfolg, Microsoft Store-Apps werden im Hintergrund aktualisiert"
|
de: "Erfolg, Microsoft Store-Apps werden im Hintergrund aktualisiert"
|
||||||
"Unable to update Microsoft Store apps, manual intervention is required":
|
|
||||||
en: "Unable to update Microsoft Store apps, manual intervention is required"
|
|
||||||
lt: "Nepavyksta atnaujinti Microsoft Store programų, reikia rankinio įsikišimo"
|
|
||||||
es: "No se pueden actualizar las aplicaciones de Microsoft Store, se requiere intervención manual"
|
|
||||||
fr: "Impossible de mettre à jour les applications du Microsoft Store, une intervention manuelle est nécessaire"
|
|
||||||
zh_CN: "无法更新 Microsoft Store 应用,需手动干预"
|
|
||||||
zh_TW: "無法更新 Microsoft Store 應用,需手動幹預"
|
|
||||||
de: "Microsoft Store-Apps können nicht aktualisiert werden, manuelles Eingreifen erforderlich"
|
|
||||||
"No JetBrains Toolbox installation found":
|
"No JetBrains Toolbox installation found":
|
||||||
en: "No JetBrains Toolbox installation found"
|
en: "No JetBrains Toolbox installation found"
|
||||||
lt: "Nerasta JetBrains Toolbox įdiegimo"
|
lt: "Nerasta JetBrains Toolbox įdiegimo"
|
||||||
@@ -1288,3 +1378,51 @@ _version: 2
|
|||||||
zh_CN: "jetbrains-toolbox-updater 在更新过程中遇到意外错误"
|
zh_CN: "jetbrains-toolbox-updater 在更新过程中遇到意外错误"
|
||||||
zh_TW: "jetbrains-toolbox-updater 在更新過程中遇到意外錯誤:"
|
zh_TW: "jetbrains-toolbox-updater 在更新過程中遇到意外錯誤:"
|
||||||
de: "jetbrains-toolbox-updater ist auf einen unerwarteten Fehler während der Aktualisierung gestoßen:"
|
de: "jetbrains-toolbox-updater ist auf einen unerwarteten Fehler während der Aktualisierung gestoßen:"
|
||||||
|
"<output from `deb-get clean` omitted>":
|
||||||
|
en: "<output from `deb-get clean` omitted>"
|
||||||
|
lt: "<išvestis iš `deb-get clean` praleista>"
|
||||||
|
es: "<salida de `deb-get clean` omitido>"
|
||||||
|
fr: "<sortie de `deb-get clean` omise>"
|
||||||
|
zh_CN: "<省略了 `deb-get clean` 的输出>"
|
||||||
|
zh_TW: "<省略了 `deb-get clean` 的輸出>"
|
||||||
|
de: "<Ausgabe von `deb-get clean` ausgelassen>"
|
||||||
|
"You have a flake inside of $FLAKE. This is deprecated for nh.":
|
||||||
|
en: "You have a flake inside of $FLAKE. This is deprecated for nh."
|
||||||
|
lt: "Jūs turite flake viduje $FLAKE. Tai yra pasenę nh."
|
||||||
|
es: "Tienes un flake dentro de $FLAKE. Esto está en desuso para nh."
|
||||||
|
fr: "Vous avez un flake à l'intérieur de $FLAKE. Ceci est obsolète pour nh."
|
||||||
|
zh_TW: "你在 $FLAKE 裡有一個 flake。這在 nh 中已被棄用。"
|
||||||
|
zh_CN: "你在 $FLAKE 里有一个 flake。这在 nh 中已被弃用。"
|
||||||
|
de: "Sie haben ein flake in $FLAKE. Dies ist für nh veraltet."
|
||||||
|
"nh cannot find any configured flakes":
|
||||||
|
en: "nh cannot find any configured flakes"
|
||||||
|
lt: "nh nepavyksta rasti jokių sukonfigūruotų flake"
|
||||||
|
es: "nh no puede encontrar ningún flake configurado"
|
||||||
|
fr: "nh ne peut trouver aucun flake configuré"
|
||||||
|
zh_TW: "nh 找不到任何已設定的 flake"
|
||||||
|
zh_CN: "nh 无法找到任何已配置的 flake"
|
||||||
|
de: "nh kann keine konfigurierten flakes finden"
|
||||||
|
"System Manuals":
|
||||||
|
en: "System Manuals"
|
||||||
|
lt: "Sistemos Vadovai"
|
||||||
|
es: "Manuales del Sistema"
|
||||||
|
fr: "Manuels du Système"
|
||||||
|
zh_CN: "系统手册"
|
||||||
|
zh_TW: "系統手冊"
|
||||||
|
de: "Systemhandbücher"
|
||||||
|
"User Manuals":
|
||||||
|
en: "User Manuals"
|
||||||
|
lt: "Vartotojo Vadovai"
|
||||||
|
es: "Manuales de Usuario"
|
||||||
|
fr: "Manuels de l'utilisateur"
|
||||||
|
zh_CN: "用户手册"
|
||||||
|
zh_TW: "使用者手冊"
|
||||||
|
de: "Benutzerhandbücher"
|
||||||
|
"ManDB isn't enabled":
|
||||||
|
en: "ManDB isn't enabled"
|
||||||
|
lt: "ManDB nėra įjungtas"
|
||||||
|
es: "ManDB no está habilitado"
|
||||||
|
fr: "ManDB n'est pas activé"
|
||||||
|
zh_CN: "ManDB 未启用"
|
||||||
|
zh_TW: "ManDB 未啟用"
|
||||||
|
de: "ManDB ist nicht aktiviert"
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ build-backend = "maturin"
|
|||||||
|
|
||||||
[project]
|
[project]
|
||||||
name = "topgrade"
|
name = "topgrade"
|
||||||
|
dynamic = ["version"]
|
||||||
requires-python = ">=3.7"
|
requires-python = ">=3.7"
|
||||||
classifiers = [
|
classifiers = [
|
||||||
"Programming Language :: Rust",
|
"Programming Language :: Rust",
|
||||||
|
|||||||
276
src/config.rs
276
src/config.rs
@@ -1,6 +1,5 @@
|
|||||||
#![allow(dead_code)]
|
#![allow(dead_code)]
|
||||||
|
|
||||||
use std::collections::BTreeMap;
|
|
||||||
use std::fs::{write, File};
|
use std::fs::{write, File};
|
||||||
use std::io::Write;
|
use std::io::Write;
|
||||||
use std::path::{Path, PathBuf};
|
use std::path::{Path, PathBuf};
|
||||||
@@ -12,16 +11,18 @@ use clap_complete::Shell;
|
|||||||
use color_eyre::eyre::Context;
|
use color_eyre::eyre::Context;
|
||||||
use color_eyre::eyre::Result;
|
use color_eyre::eyre::Result;
|
||||||
use etcetera::base_strategy::BaseStrategy;
|
use etcetera::base_strategy::BaseStrategy;
|
||||||
|
use indexmap::IndexMap;
|
||||||
use merge::Merge;
|
use merge::Merge;
|
||||||
use regex::Regex;
|
use regex::Regex;
|
||||||
use regex_split::RegexSplit;
|
use regex_split::RegexSplit;
|
||||||
use rust_i18n::t;
|
use rust_i18n::t;
|
||||||
use serde::Deserialize;
|
use serde::Deserialize;
|
||||||
use strum::{EnumIter, EnumString, IntoEnumIterator, VariantNames};
|
use strum::IntoEnumIterator;
|
||||||
use which_crate::which;
|
use which_crate::which;
|
||||||
|
|
||||||
use super::utils::editor;
|
use super::utils::editor;
|
||||||
use crate::command::CommandExt;
|
use crate::command::CommandExt;
|
||||||
|
use crate::step::Step;
|
||||||
use crate::sudo::SudoKind;
|
use crate::sudo::SudoKind;
|
||||||
use crate::utils::string_prepend_str;
|
use crate::utils::string_prepend_str;
|
||||||
use tracing::{debug, error};
|
use tracing::{debug, error};
|
||||||
@@ -44,139 +45,7 @@ macro_rules! str_value {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
pub type Commands = BTreeMap<String, String>;
|
pub type Commands = IndexMap<String, String>;
|
||||||
|
|
||||||
#[derive(ValueEnum, EnumString, VariantNames, Debug, Clone, PartialEq, Eq, Deserialize, EnumIter, Copy)]
|
|
||||||
#[clap(rename_all = "snake_case")]
|
|
||||||
#[serde(rename_all = "snake_case")]
|
|
||||||
#[strum(serialize_all = "snake_case")]
|
|
||||||
pub enum Step {
|
|
||||||
AM,
|
|
||||||
AppMan,
|
|
||||||
Asdf,
|
|
||||||
Atom,
|
|
||||||
Aqua,
|
|
||||||
Audit,
|
|
||||||
AutoCpufreq,
|
|
||||||
Bin,
|
|
||||||
Bob,
|
|
||||||
BrewCask,
|
|
||||||
BrewFormula,
|
|
||||||
Bun,
|
|
||||||
BunPackages,
|
|
||||||
Cargo,
|
|
||||||
Certbot,
|
|
||||||
Chezmoi,
|
|
||||||
Chocolatey,
|
|
||||||
Choosenim,
|
|
||||||
CinnamonSpices,
|
|
||||||
ClamAvDb,
|
|
||||||
Composer,
|
|
||||||
Conda,
|
|
||||||
ConfigUpdate,
|
|
||||||
Containers,
|
|
||||||
CustomCommands,
|
|
||||||
DebGet,
|
|
||||||
Deno,
|
|
||||||
Distrobox,
|
|
||||||
DkpPacman,
|
|
||||||
Dotnet,
|
|
||||||
Elan,
|
|
||||||
Emacs,
|
|
||||||
Firmware,
|
|
||||||
Flatpak,
|
|
||||||
Flutter,
|
|
||||||
Fossil,
|
|
||||||
Gcloud,
|
|
||||||
Gem,
|
|
||||||
Ghcup,
|
|
||||||
GithubCliExtensions,
|
|
||||||
GitRepos,
|
|
||||||
GnomeShellExtensions,
|
|
||||||
Go,
|
|
||||||
Guix,
|
|
||||||
Haxelib,
|
|
||||||
Helm,
|
|
||||||
HomeManager,
|
|
||||||
JetBrainsToolbox,
|
|
||||||
Jetpack,
|
|
||||||
Julia,
|
|
||||||
Juliaup,
|
|
||||||
Kakoune,
|
|
||||||
Helix,
|
|
||||||
Krew,
|
|
||||||
Lure,
|
|
||||||
Lensfun,
|
|
||||||
Macports,
|
|
||||||
Mamba,
|
|
||||||
Miktex,
|
|
||||||
Mas,
|
|
||||||
Maza,
|
|
||||||
Micro,
|
|
||||||
MicrosoftStore,
|
|
||||||
Mise,
|
|
||||||
Myrepos,
|
|
||||||
Nix,
|
|
||||||
Node,
|
|
||||||
Opam,
|
|
||||||
Pacdef,
|
|
||||||
Pacstall,
|
|
||||||
Pearl,
|
|
||||||
Pip3,
|
|
||||||
PipReview,
|
|
||||||
PipReviewLocal,
|
|
||||||
Pipupgrade,
|
|
||||||
Pipx,
|
|
||||||
Pipxu,
|
|
||||||
Pixi,
|
|
||||||
Pkg,
|
|
||||||
Pkgin,
|
|
||||||
PlatformioCore,
|
|
||||||
Pnpm,
|
|
||||||
Poetry,
|
|
||||||
Powershell,
|
|
||||||
Protonup,
|
|
||||||
Pyenv,
|
|
||||||
Raco,
|
|
||||||
Rcm,
|
|
||||||
Remotes,
|
|
||||||
Restarts,
|
|
||||||
Rtcl,
|
|
||||||
RubyGems,
|
|
||||||
Rustup,
|
|
||||||
Rye,
|
|
||||||
Scoop,
|
|
||||||
Sdkman,
|
|
||||||
SelfUpdate,
|
|
||||||
Sheldon,
|
|
||||||
Shell,
|
|
||||||
Snap,
|
|
||||||
Sparkle,
|
|
||||||
Spicetify,
|
|
||||||
Stack,
|
|
||||||
Stew,
|
|
||||||
System,
|
|
||||||
Tldr,
|
|
||||||
Tlmgr,
|
|
||||||
Tmux,
|
|
||||||
Toolbx,
|
|
||||||
Uv,
|
|
||||||
Vagrant,
|
|
||||||
Vcpkg,
|
|
||||||
Vim,
|
|
||||||
VoltaPackages,
|
|
||||||
Vscode,
|
|
||||||
Vscodium,
|
|
||||||
Waydroid,
|
|
||||||
Winget,
|
|
||||||
Wsl,
|
|
||||||
WslUpdate,
|
|
||||||
Xcodes,
|
|
||||||
Yadm,
|
|
||||||
Yarn,
|
|
||||||
Zigup,
|
|
||||||
Zvm,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Deserialize, Default, Debug, Merge)]
|
#[derive(Deserialize, Default, Debug, Merge)]
|
||||||
#[serde(deny_unknown_fields)]
|
#[serde(deny_unknown_fields)]
|
||||||
@@ -193,6 +62,12 @@ pub struct Containers {
|
|||||||
runtime: Option<ContainerRuntime>,
|
runtime: Option<ContainerRuntime>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Deserialize, Default, Debug, Merge)]
|
||||||
|
#[serde(deny_unknown_fields)]
|
||||||
|
pub struct Mandb {
|
||||||
|
enable: Option<bool>,
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Deserialize, Default, Debug, Merge)]
|
#[derive(Deserialize, Default, Debug, Merge)]
|
||||||
#[serde(deny_unknown_fields)]
|
#[serde(deny_unknown_fields)]
|
||||||
pub struct Git {
|
pub struct Git {
|
||||||
@@ -217,15 +92,26 @@ pub struct Vagrant {
|
|||||||
always_suspend: Option<bool>,
|
always_suspend: Option<bool>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Deserialize, Default, Debug, Copy, Clone)]
|
||||||
|
#[serde(rename_all = "snake_case")]
|
||||||
|
pub enum UpdatesAutoReboot {
|
||||||
|
Yes,
|
||||||
|
#[default]
|
||||||
|
No,
|
||||||
|
Ask,
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Deserialize, Default, Debug, Merge)]
|
#[derive(Deserialize, Default, Debug, Merge)]
|
||||||
#[serde(deny_unknown_fields)]
|
#[serde(deny_unknown_fields)]
|
||||||
pub struct Windows {
|
pub struct Windows {
|
||||||
accept_all_updates: Option<bool>,
|
accept_all_updates: Option<bool>,
|
||||||
|
updates_auto_reboot: Option<UpdatesAutoReboot>,
|
||||||
self_rename: Option<bool>,
|
self_rename: Option<bool>,
|
||||||
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>,
|
winget_silent_install: Option<bool>,
|
||||||
|
winget_use_sudo: Option<bool>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Deserialize, Default, Debug, Merge)]
|
#[derive(Deserialize, Default, Debug, Merge)]
|
||||||
@@ -238,6 +124,16 @@ pub struct Python {
|
|||||||
poetry_force_self_update: Option<bool>,
|
poetry_force_self_update: Option<bool>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Deserialize, Default, Debug, Merge)]
|
||||||
|
#[serde(deny_unknown_fields)]
|
||||||
|
pub struct Conda {
|
||||||
|
#[merge(strategy = crate::utils::merge_strategies::vec_prepend_opt)]
|
||||||
|
env_names: Option<Vec<String>>,
|
||||||
|
|
||||||
|
#[merge(strategy = crate::utils::merge_strategies::vec_prepend_opt)]
|
||||||
|
env_paths: Option<Vec<String>>,
|
||||||
|
}
|
||||||
|
|
||||||
#[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)]
|
||||||
@@ -283,6 +179,13 @@ pub struct Flatpak {
|
|||||||
use_sudo: Option<bool>,
|
use_sudo: Option<bool>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Deserialize, Default, Debug, Merge)]
|
||||||
|
#[serde(deny_unknown_fields)]
|
||||||
|
#[allow(clippy::upper_case_acronyms)]
|
||||||
|
pub struct Pixi {
|
||||||
|
include_release_notes: Option<bool>,
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Deserialize, Default, Debug, Merge)]
|
#[derive(Deserialize, Default, Debug, Merge)]
|
||||||
#[serde(deny_unknown_fields)]
|
#[serde(deny_unknown_fields)]
|
||||||
pub struct Brew {
|
pub struct Brew {
|
||||||
@@ -392,6 +295,8 @@ pub struct Vim {
|
|||||||
#[derive(Deserialize, Default, Debug, Merge)]
|
#[derive(Deserialize, Default, Debug, Merge)]
|
||||||
#[serde(deny_unknown_fields)]
|
#[serde(deny_unknown_fields)]
|
||||||
pub struct Misc {
|
pub struct Misc {
|
||||||
|
allow_root: Option<bool>,
|
||||||
|
|
||||||
pre_sudo: Option<bool>,
|
pre_sudo: Option<bool>,
|
||||||
|
|
||||||
sudo_command: Option<SudoKind>,
|
sudo_command: Option<SudoKind>,
|
||||||
@@ -421,6 +326,8 @@ pub struct Misc {
|
|||||||
|
|
||||||
no_retry: Option<bool>,
|
no_retry: Option<bool>,
|
||||||
|
|
||||||
|
show_skipped: Option<bool>,
|
||||||
|
|
||||||
run_in_tmux: Option<bool>,
|
run_in_tmux: Option<bool>,
|
||||||
|
|
||||||
tmux_session_mode: Option<TmuxSessionMode>,
|
tmux_session_mode: Option<TmuxSessionMode>,
|
||||||
@@ -500,6 +407,9 @@ pub struct ConfigFile {
|
|||||||
#[merge(strategy = crate::utils::merge_strategies::commands_merge_opt)]
|
#[merge(strategy = crate::utils::merge_strategies::commands_merge_opt)]
|
||||||
commands: Option<Commands>,
|
commands: Option<Commands>,
|
||||||
|
|
||||||
|
#[merge(strategy = crate::utils::merge_strategies::inner_merge_opt)]
|
||||||
|
conda: Option<Conda>,
|
||||||
|
|
||||||
#[merge(strategy = crate::utils::merge_strategies::inner_merge_opt)]
|
#[merge(strategy = crate::utils::merge_strategies::inner_merge_opt)]
|
||||||
python: Option<Python>,
|
python: Option<Python>,
|
||||||
|
|
||||||
@@ -512,6 +422,9 @@ pub struct ConfigFile {
|
|||||||
#[merge(strategy = crate::utils::merge_strategies::inner_merge_opt)]
|
#[merge(strategy = crate::utils::merge_strategies::inner_merge_opt)]
|
||||||
linux: Option<Linux>,
|
linux: Option<Linux>,
|
||||||
|
|
||||||
|
#[merge(strategy = crate::utils::merge_strategies::inner_merge_opt)]
|
||||||
|
mandb: Option<Mandb>,
|
||||||
|
|
||||||
#[merge(strategy = crate::utils::merge_strategies::inner_merge_opt)]
|
#[merge(strategy = crate::utils::merge_strategies::inner_merge_opt)]
|
||||||
git: Option<Git>,
|
git: Option<Git>,
|
||||||
|
|
||||||
@@ -542,6 +455,9 @@ pub struct ConfigFile {
|
|||||||
#[merge(strategy = crate::utils::merge_strategies::inner_merge_opt)]
|
#[merge(strategy = crate::utils::merge_strategies::inner_merge_opt)]
|
||||||
flatpak: Option<Flatpak>,
|
flatpak: Option<Flatpak>,
|
||||||
|
|
||||||
|
#[merge(strategy = crate::utils::merge_strategies::inner_merge_opt)]
|
||||||
|
pixi: Option<Pixi>,
|
||||||
|
|
||||||
#[merge(strategy = crate::utils::merge_strategies::inner_merge_opt)]
|
#[merge(strategy = crate::utils::merge_strategies::inner_merge_opt)]
|
||||||
distrobox: Option<Distrobox>,
|
distrobox: Option<Distrobox>,
|
||||||
|
|
||||||
@@ -783,6 +699,10 @@ pub struct CommandLineArgs {
|
|||||||
#[arg(short = 't', long = "tmux")]
|
#[arg(short = 't', long = "tmux")]
|
||||||
run_in_tmux: bool,
|
run_in_tmux: bool,
|
||||||
|
|
||||||
|
/// Don't run inside tmux
|
||||||
|
#[arg(long = "no-tmux")]
|
||||||
|
no_tmux: bool,
|
||||||
|
|
||||||
/// Cleanup temporary or old files
|
/// Cleanup temporary or old files
|
||||||
#[arg(short = 'c', long = "cleanup")]
|
#[arg(short = 'c', long = "cleanup")]
|
||||||
cleanup: bool,
|
cleanup: bool,
|
||||||
@@ -849,6 +769,10 @@ pub struct CommandLineArgs {
|
|||||||
#[arg(long = "show-skipped")]
|
#[arg(long = "show-skipped")]
|
||||||
show_skipped: bool,
|
show_skipped: bool,
|
||||||
|
|
||||||
|
/// Suppress warning and confirmation prompt if running as root
|
||||||
|
#[arg(long = "allow-root")]
|
||||||
|
allow_root: bool,
|
||||||
|
|
||||||
/// Tracing filter directives.
|
/// Tracing filter directives.
|
||||||
///
|
///
|
||||||
/// See: https://docs.rs/tracing-subscriber/latest/tracing_subscriber/filter/struct.EnvFilter.html#directives
|
/// See: https://docs.rs/tracing-subscriber/latest/tracing_subscriber/filter/struct.EnvFilter.html#directives
|
||||||
@@ -962,6 +886,22 @@ impl Config {
|
|||||||
&self.config_file.commands
|
&self.config_file.commands
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// The list of additional named conda environments.
|
||||||
|
pub fn conda_env_names(&self) -> Option<&Vec<String>> {
|
||||||
|
self.config_file
|
||||||
|
.conda
|
||||||
|
.as_ref()
|
||||||
|
.and_then(|conda| conda.env_names.as_ref())
|
||||||
|
}
|
||||||
|
|
||||||
|
/// The list of additional conda environment paths.
|
||||||
|
pub fn conda_env_paths(&self) -> Option<&Vec<String>> {
|
||||||
|
self.config_file
|
||||||
|
.conda
|
||||||
|
.as_ref()
|
||||||
|
.and_then(|conda| conda.env_paths.as_ref())
|
||||||
|
}
|
||||||
|
|
||||||
/// The list of additional git repositories to pull.
|
/// The list of additional git repositories to pull.
|
||||||
pub fn git_repos(&self) -> Option<&Vec<String>> {
|
pub fn git_repos(&self) -> Option<&Vec<String>> {
|
||||||
self.config_file.git.as_ref().and_then(|git| git.repos.as_ref())
|
self.config_file.git.as_ref().and_then(|git| git.repos.as_ref())
|
||||||
@@ -1031,13 +971,14 @@ impl Config {
|
|||||||
|
|
||||||
/// Tell whether we should run in tmux.
|
/// Tell whether we should run in tmux.
|
||||||
pub fn run_in_tmux(&self) -> bool {
|
pub fn run_in_tmux(&self) -> bool {
|
||||||
self.opt.run_in_tmux
|
!self.opt.no_tmux
|
||||||
|| self
|
&& (self.opt.run_in_tmux
|
||||||
.config_file
|
|| self
|
||||||
.misc
|
.config_file
|
||||||
.as_ref()
|
.misc
|
||||||
.and_then(|misc| misc.run_in_tmux)
|
.as_ref()
|
||||||
.unwrap_or(false)
|
.and_then(|misc| misc.run_in_tmux)
|
||||||
|
.unwrap_or(false))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The preferred way to run the new tmux session.
|
/// The preferred way to run the new tmux session.
|
||||||
@@ -1191,6 +1132,15 @@ impl Config {
|
|||||||
.unwrap_or(true)
|
.unwrap_or(true)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Whether to auto reboot for Windows updates that require it
|
||||||
|
pub fn windows_updates_auto_reboot(&self) -> UpdatesAutoReboot {
|
||||||
|
self.config_file
|
||||||
|
.windows
|
||||||
|
.as_ref()
|
||||||
|
.and_then(|windows| windows.updates_auto_reboot)
|
||||||
|
.unwrap_or_default()
|
||||||
|
}
|
||||||
|
|
||||||
/// Whether to self rename the Topgrade executable during the run
|
/// Whether to self rename the Topgrade executable during the run
|
||||||
pub fn self_rename(&self) -> bool {
|
pub fn self_rename(&self) -> bool {
|
||||||
self.config_file
|
self.config_file
|
||||||
@@ -1218,6 +1168,15 @@ impl Config {
|
|||||||
.unwrap_or(false)
|
.unwrap_or(false)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Should use sudo for Winget
|
||||||
|
pub fn winget_use_sudo(&self) -> bool {
|
||||||
|
self.config_file
|
||||||
|
.windows
|
||||||
|
.as_ref()
|
||||||
|
.and_then(|w| w.winget_use_sudo)
|
||||||
|
.unwrap_or(false)
|
||||||
|
}
|
||||||
|
|
||||||
/// Whether Brew cask should be greedy
|
/// Whether Brew cask should be greedy
|
||||||
pub fn brew_cask_greedy(&self) -> bool {
|
pub fn brew_cask_greedy(&self) -> bool {
|
||||||
self.config_file
|
self.config_file
|
||||||
@@ -1327,6 +1286,15 @@ impl Config {
|
|||||||
.unwrap_or("")
|
.unwrap_or("")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Show release notes of latest pixi release
|
||||||
|
pub fn show_pixi_release_notes(&self) -> bool {
|
||||||
|
self.config_file
|
||||||
|
.pixi
|
||||||
|
.as_ref()
|
||||||
|
.and_then(|s| s.include_release_notes)
|
||||||
|
.unwrap_or(false)
|
||||||
|
}
|
||||||
|
|
||||||
/// Show news on Arch Linux
|
/// Show news on Arch Linux
|
||||||
pub fn show_arch_news(&self) -> bool {
|
pub fn show_arch_news(&self) -> bool {
|
||||||
self.config_file
|
self.config_file
|
||||||
@@ -1541,6 +1509,20 @@ impl Config {
|
|||||||
|
|
||||||
pub fn show_skipped(&self) -> bool {
|
pub fn show_skipped(&self) -> bool {
|
||||||
self.opt.show_skipped
|
self.opt.show_skipped
|
||||||
|
|| self
|
||||||
|
.config_file
|
||||||
|
.misc
|
||||||
|
.as_ref()
|
||||||
|
.and_then(|misc| misc.show_skipped)
|
||||||
|
.unwrap_or(false)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn enable_mandb(&self) -> bool {
|
||||||
|
self.config_file
|
||||||
|
.mandb
|
||||||
|
.as_ref()
|
||||||
|
.and_then(|mandb| mandb.enable)
|
||||||
|
.unwrap_or(false)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn open_remotes_in_new_terminal(&self) -> bool {
|
pub fn open_remotes_in_new_terminal(&self) -> bool {
|
||||||
@@ -1559,6 +1541,16 @@ impl Config {
|
|||||||
.unwrap_or(true)
|
.unwrap_or(true)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn allow_root(&self) -> bool {
|
||||||
|
self.opt.allow_root
|
||||||
|
|| self
|
||||||
|
.config_file
|
||||||
|
.misc
|
||||||
|
.as_ref()
|
||||||
|
.and_then(|misc| misc.allow_root)
|
||||||
|
.unwrap_or(false)
|
||||||
|
}
|
||||||
|
|
||||||
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)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,22 +1,21 @@
|
|||||||
//! 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 winapi::shared::minwindef::{BOOL, DWORD, FALSE, TRUE};
|
use windows::core::BOOL;
|
||||||
use winapi::um::consoleapi::SetConsoleCtrlHandler;
|
use windows::Win32::System::Console::{SetConsoleCtrlHandler, CTRL_C_EVENT};
|
||||||
use winapi::um::wincon::CTRL_C_EVENT;
|
|
||||||
|
|
||||||
extern "system" fn handler(ctrl_type: DWORD) -> BOOL {
|
extern "system" fn handler(ctrl_type: u32) -> BOOL {
|
||||||
match ctrl_type {
|
match ctrl_type {
|
||||||
CTRL_C_EVENT => {
|
CTRL_C_EVENT => {
|
||||||
set_interrupted();
|
set_interrupted();
|
||||||
TRUE
|
true.into()
|
||||||
}
|
}
|
||||||
_ => FALSE,
|
_ => false.into(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn set_handler() {
|
pub fn set_handler() {
|
||||||
if 0 == unsafe { SetConsoleCtrlHandler(Some(handler), TRUE) } {
|
if let Err(e) = unsafe { SetConsoleCtrlHandler(Some(handler), true) } {
|
||||||
error!("Cannot set a control C handler")
|
error!("Cannot set a control C handler: {e}")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
31
src/error.rs
31
src/error.rs
@@ -3,6 +3,8 @@ use std::{fmt::Display, process::ExitStatus};
|
|||||||
use rust_i18n::t;
|
use rust_i18n::t;
|
||||||
use thiserror::Error;
|
use thiserror::Error;
|
||||||
|
|
||||||
|
use crate::sudo::SudoKind;
|
||||||
|
|
||||||
#[derive(Error, Debug, PartialEq, Eq)]
|
#[derive(Error, Debug, PartialEq, Eq)]
|
||||||
pub enum TopgradeError {
|
pub enum TopgradeError {
|
||||||
ProcessFailed(String, ExitStatus),
|
ProcessFailed(String, ExitStatus),
|
||||||
@@ -68,6 +70,35 @@ impl Display for StepFailed {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Error, Debug)]
|
||||||
|
pub struct UnsupportedSudo<'a> {
|
||||||
|
pub sudo_kind: SudoKind,
|
||||||
|
pub option: &'a str,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Display for UnsupportedSudo<'_> {
|
||||||
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
|
write!(
|
||||||
|
f,
|
||||||
|
"{}",
|
||||||
|
t!(
|
||||||
|
"{sudo_kind} does not support the {option} option",
|
||||||
|
sudo_kind = self.sudo_kind,
|
||||||
|
option = self.option
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Error, Debug)]
|
||||||
|
pub struct MissingSudo();
|
||||||
|
|
||||||
|
impl Display for MissingSudo {
|
||||||
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
|
write!(f, "{}", t!("Could not find sudo"))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Error, Debug)]
|
#[derive(Error, Debug)]
|
||||||
pub struct DryRun();
|
pub struct DryRun();
|
||||||
|
|
||||||
|
|||||||
@@ -1,12 +1,48 @@
|
|||||||
#![allow(dead_code)]
|
#![allow(dead_code)]
|
||||||
use crate::executor::RunType;
|
|
||||||
use crate::sudo::Sudo;
|
|
||||||
use crate::utils::{get_require_sudo_string, require_option};
|
|
||||||
use crate::{config::Config, executor::Executor};
|
|
||||||
use color_eyre::eyre::Result;
|
use color_eyre::eyre::Result;
|
||||||
|
use rust_i18n::t;
|
||||||
use std::env::var;
|
use std::env::var;
|
||||||
use std::path::Path;
|
use std::ffi::OsStr;
|
||||||
use std::sync::Mutex;
|
use std::process::Command;
|
||||||
|
use std::sync::{LazyLock, Mutex};
|
||||||
|
|
||||||
|
use crate::config::Config;
|
||||||
|
use crate::error::MissingSudo;
|
||||||
|
use crate::executor::{DryCommand, Executor};
|
||||||
|
use crate::powershell::Powershell;
|
||||||
|
#[cfg(target_os = "linux")]
|
||||||
|
use crate::steps::linux::Distribution;
|
||||||
|
use crate::sudo::Sudo;
|
||||||
|
use crate::utils::require_option;
|
||||||
|
|
||||||
|
/// An enum telling whether Topgrade should perform dry runs or actually perform the steps.
|
||||||
|
#[derive(Clone, Copy, Debug)]
|
||||||
|
pub enum RunType {
|
||||||
|
/// Executing commands will just print the command with its argument.
|
||||||
|
Dry,
|
||||||
|
|
||||||
|
/// Executing commands will perform actual execution.
|
||||||
|
Wet,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl RunType {
|
||||||
|
/// Create a new instance from a boolean telling whether to dry run.
|
||||||
|
pub fn new(dry_run: bool) -> Self {
|
||||||
|
if dry_run {
|
||||||
|
RunType::Dry
|
||||||
|
} else {
|
||||||
|
RunType::Wet
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Tells whether we're performing a dry run.
|
||||||
|
pub fn dry(self) -> bool {
|
||||||
|
match self {
|
||||||
|
RunType::Dry => true,
|
||||||
|
RunType::Wet => false,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub struct ExecutionContext<'a> {
|
pub struct ExecutionContext<'a> {
|
||||||
run_type: RunType,
|
run_type: RunType,
|
||||||
@@ -18,10 +54,18 @@ pub struct ExecutionContext<'a> {
|
|||||||
tmux_session: Mutex<Option<String>>,
|
tmux_session: Mutex<Option<String>>,
|
||||||
/// True if topgrade is running under ssh.
|
/// True if topgrade is running under ssh.
|
||||||
under_ssh: bool,
|
under_ssh: bool,
|
||||||
|
#[cfg(target_os = "linux")]
|
||||||
|
distribution: &'a Result<Distribution>,
|
||||||
|
powershell: LazyLock<Option<Powershell>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> ExecutionContext<'a> {
|
impl<'a> ExecutionContext<'a> {
|
||||||
pub fn new(run_type: RunType, sudo: Option<Sudo>, config: &'a Config) -> Self {
|
pub fn new(
|
||||||
|
run_type: RunType,
|
||||||
|
sudo: Option<Sudo>,
|
||||||
|
config: &'a Config,
|
||||||
|
#[cfg(target_os = "linux")] distribution: &'a Result<Distribution>,
|
||||||
|
) -> Self {
|
||||||
let under_ssh = var("SSH_CLIENT").is_ok() || var("SSH_TTY").is_ok();
|
let under_ssh = var("SSH_CLIENT").is_ok() || var("SSH_TTY").is_ok();
|
||||||
Self {
|
Self {
|
||||||
run_type,
|
run_type,
|
||||||
@@ -29,12 +73,18 @@ impl<'a> ExecutionContext<'a> {
|
|||||||
config,
|
config,
|
||||||
tmux_session: Mutex::new(None),
|
tmux_session: Mutex::new(None),
|
||||||
under_ssh,
|
under_ssh,
|
||||||
|
#[cfg(target_os = "linux")]
|
||||||
|
distribution,
|
||||||
|
powershell: LazyLock::new(Powershell::new),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn execute_elevated(&self, command: &Path, interactive: bool) -> Result<Executor> {
|
/// Create an instance of `Executor` that should run `program`.
|
||||||
let sudo = require_option(self.sudo.as_ref(), get_require_sudo_string())?;
|
pub fn execute<S: AsRef<OsStr>>(&self, program: S) -> Executor {
|
||||||
Ok(sudo.execute_elevated(self, command, interactive))
|
match self.run_type {
|
||||||
|
RunType::Dry => Executor::Dry(DryCommand::new(program)),
|
||||||
|
RunType::Wet => Executor::Wet(Command::new(program)),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn run_type(&self) -> RunType {
|
pub fn run_type(&self) -> RunType {
|
||||||
@@ -45,6 +95,14 @@ impl<'a> ExecutionContext<'a> {
|
|||||||
&self.sudo
|
&self.sudo
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn require_sudo(&self) -> Result<&Sudo> {
|
||||||
|
if let Some(value) = self.sudo() {
|
||||||
|
Ok(value)
|
||||||
|
} else {
|
||||||
|
Err(MissingSudo().into())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn config(&self) -> &Config {
|
pub fn config(&self) -> &Config {
|
||||||
self.config
|
self.config
|
||||||
}
|
}
|
||||||
@@ -60,4 +118,17 @@ impl<'a> ExecutionContext<'a> {
|
|||||||
pub fn get_tmux_session(&self) -> Option<String> {
|
pub fn get_tmux_session(&self) -> Option<String> {
|
||||||
self.tmux_session.lock().unwrap().clone()
|
self.tmux_session.lock().unwrap().clone()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(target_os = "linux")]
|
||||||
|
pub fn distribution(&self) -> &Result<Distribution> {
|
||||||
|
self.distribution
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn powershell(&self) -> &Option<Powershell> {
|
||||||
|
&self.powershell
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn require_powershell(&self) -> Result<&Powershell> {
|
||||||
|
require_option(self.powershell.as_ref(), t!("Powershell is not installed").to_string())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -10,46 +10,6 @@ use tracing::debug;
|
|||||||
use crate::command::CommandExt;
|
use crate::command::CommandExt;
|
||||||
use crate::error::DryRun;
|
use crate::error::DryRun;
|
||||||
|
|
||||||
/// An enum telling whether Topgrade should perform dry runs or actually perform the steps.
|
|
||||||
#[derive(Clone, Copy, Debug)]
|
|
||||||
pub enum RunType {
|
|
||||||
/// Executing commands will just print the command with its argument.
|
|
||||||
Dry,
|
|
||||||
|
|
||||||
/// Executing commands will perform actual execution.
|
|
||||||
Wet,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl RunType {
|
|
||||||
/// Create a new instance from a boolean telling whether to dry run.
|
|
||||||
pub fn new(dry_run: bool) -> Self {
|
|
||||||
if dry_run {
|
|
||||||
RunType::Dry
|
|
||||||
} else {
|
|
||||||
RunType::Wet
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Create an instance of `Executor` that should run `program`.
|
|
||||||
pub fn execute<S: AsRef<OsStr>>(self, program: S) -> Executor {
|
|
||||||
match self {
|
|
||||||
RunType::Dry => Executor::Dry(DryCommand {
|
|
||||||
program: program.as_ref().into(),
|
|
||||||
..Default::default()
|
|
||||||
}),
|
|
||||||
RunType::Wet => Executor::Wet(Command::new(program)),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Tells whether we're performing a dry run.
|
|
||||||
pub fn dry(self) -> bool {
|
|
||||||
match self {
|
|
||||||
RunType::Dry => true,
|
|
||||||
RunType::Wet => false,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// An enum providing a similar interface to `std::process::Command`.
|
/// An enum providing a similar interface to `std::process::Command`.
|
||||||
/// If the enum is set to `Wet`, execution will be performed with `std::process::Command`.
|
/// If the enum is set to `Wet`, execution will be performed with `std::process::Command`.
|
||||||
/// If the enum is set to `Dry`, execution will just print the command with its arguments.
|
/// If the enum is set to `Dry`, execution will just print the command with its arguments.
|
||||||
@@ -207,8 +167,7 @@ pub enum ExecutorOutput {
|
|||||||
Dry,
|
Dry,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A struct represending a command. Trying to execute it will just print its arguments.
|
/// A struct representing a command. Trying to execute it will just print its arguments.
|
||||||
#[derive(Default)]
|
|
||||||
pub struct DryCommand {
|
pub struct DryCommand {
|
||||||
program: OsString,
|
program: OsString,
|
||||||
args: Vec<OsString>,
|
args: Vec<OsString>,
|
||||||
@@ -216,6 +175,14 @@ pub struct DryCommand {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl DryCommand {
|
impl DryCommand {
|
||||||
|
pub fn new<S: AsRef<OsStr>>(program: S) -> Self {
|
||||||
|
Self {
|
||||||
|
program: program.as_ref().to_os_string(),
|
||||||
|
args: Vec::new(),
|
||||||
|
directory: None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn dry_run(&self) {
|
fn dry_run(&self) {
|
||||||
print!(
|
print!(
|
||||||
"{}",
|
"{}",
|
||||||
|
|||||||
423
src/main.rs
423
src/main.rs
@@ -17,20 +17,21 @@ use etcetera::base_strategy::BaseStrategy;
|
|||||||
use etcetera::base_strategy::Windows;
|
use etcetera::base_strategy::Windows;
|
||||||
#[cfg(unix)]
|
#[cfg(unix)]
|
||||||
use etcetera::base_strategy::Xdg;
|
use etcetera::base_strategy::Xdg;
|
||||||
use once_cell::sync::Lazy;
|
|
||||||
use rust_i18n::{i18n, t};
|
use rust_i18n::{i18n, t};
|
||||||
|
use std::sync::LazyLock;
|
||||||
use tracing::debug;
|
use tracing::debug;
|
||||||
|
|
||||||
use self::config::{CommandLineArgs, Config, Step};
|
use self::config::{CommandLineArgs, Config};
|
||||||
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;
|
||||||
|
use self::runner::StepResult;
|
||||||
#[allow(clippy::wildcard_imports)]
|
#[allow(clippy::wildcard_imports)]
|
||||||
use self::steps::{remote::*, *};
|
use self::steps::{remote::*, *};
|
||||||
|
use self::sudo::{Sudo, SudoCreateError, SudoKind};
|
||||||
#[allow(clippy::wildcard_imports)]
|
#[allow(clippy::wildcard_imports)]
|
||||||
use self::terminal::*;
|
use self::terminal::*;
|
||||||
|
use self::utils::{install_color_eyre, install_tracing, is_elevated, update_tracing};
|
||||||
use self::utils::{hostname, install_color_eyre, install_tracing, update_tracing};
|
|
||||||
|
|
||||||
mod breaking_changes;
|
mod breaking_changes;
|
||||||
mod command;
|
mod command;
|
||||||
@@ -39,23 +40,23 @@ mod ctrlc;
|
|||||||
mod error;
|
mod error;
|
||||||
mod execution_context;
|
mod execution_context;
|
||||||
mod executor;
|
mod executor;
|
||||||
mod report;
|
|
||||||
mod runner;
|
mod runner;
|
||||||
#[cfg(windows)]
|
#[cfg(windows)]
|
||||||
mod self_renamer;
|
mod self_renamer;
|
||||||
#[cfg(feature = "self-update")]
|
#[cfg(feature = "self-update")]
|
||||||
mod self_update;
|
mod self_update;
|
||||||
|
mod step;
|
||||||
mod steps;
|
mod steps;
|
||||||
mod sudo;
|
mod sudo;
|
||||||
mod terminal;
|
mod terminal;
|
||||||
mod utils;
|
mod utils;
|
||||||
|
|
||||||
pub(crate) static HOME_DIR: Lazy<PathBuf> = Lazy::new(|| home::home_dir().expect("No home directory"));
|
pub(crate) static HOME_DIR: LazyLock<PathBuf> = LazyLock::new(|| home::home_dir().expect("No home directory"));
|
||||||
#[cfg(unix)]
|
#[cfg(unix)]
|
||||||
pub(crate) static XDG_DIRS: Lazy<Xdg> = Lazy::new(|| Xdg::new().expect("No home directory"));
|
pub(crate) static XDG_DIRS: LazyLock<Xdg> = LazyLock::new(|| Xdg::new().expect("No home directory"));
|
||||||
|
|
||||||
#[cfg(windows)]
|
#[cfg(windows)]
|
||||||
pub(crate) static WINDOWS_DIRS: Lazy<Windows> = Lazy::new(|| Windows::new().expect("No home directory"));
|
pub(crate) static WINDOWS_DIRS: LazyLock<Windows> = LazyLock::new(|| Windows::new().expect("No home directory"));
|
||||||
|
|
||||||
// Init and load the i18n files
|
// Init and load the i18n files
|
||||||
i18n!("locales", fallback = "en");
|
i18n!("locales", fallback = "en");
|
||||||
@@ -97,9 +98,9 @@ fn run() -> Result<()> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
for env in opt.env_variables() {
|
for env in opt.env_variables() {
|
||||||
let mut splitted = env.split('=');
|
let mut parts = env.split('=');
|
||||||
let var = splitted.next().unwrap();
|
let var = parts.next().unwrap();
|
||||||
let value = splitted.next().unwrap();
|
let value = parts.next().unwrap();
|
||||||
env::set_var(var, value);
|
env::set_var(var, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -122,7 +123,7 @@ fn run() -> Result<()> {
|
|||||||
|
|
||||||
debug!("Version: {}", crate_version!());
|
debug!("Version: {}", crate_version!());
|
||||||
debug!("OS: {}", env!("TARGET"));
|
debug!("OS: {}", env!("TARGET"));
|
||||||
debug!("{:?}", std::env::args());
|
debug!("{:?}", env::args());
|
||||||
debug!("Binary path: {:?}", std::env::current_exe());
|
debug!("Binary path: {:?}", std::env::current_exe());
|
||||||
debug!("self-update Feature Enabled: {:?}", cfg!(feature = "self-update"));
|
debug!("self-update Feature Enabled: {:?}", cfg!(feature = "self-update"));
|
||||||
debug!("Configuration: {:?}", config);
|
debug!("Configuration: {:?}", config);
|
||||||
@@ -135,27 +136,53 @@ fn run() -> Result<()> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let powershell = powershell::Powershell::new();
|
let elevated = is_elevated();
|
||||||
let should_run_powershell = powershell.profile().is_some() && config.should_run(Step::Powershell);
|
|
||||||
let emacs = emacs::Emacs::new();
|
#[cfg(unix)]
|
||||||
|
if !config.allow_root() && elevated {
|
||||||
|
print_warning(t!(
|
||||||
|
"Topgrade should not be run as root, it will run commands with sudo or equivalent where needed."
|
||||||
|
));
|
||||||
|
if !prompt_yesno(&t!("Continue?"))? {
|
||||||
|
exit(1)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let sudo = match config.sudo_command() {
|
||||||
|
Some(kind) => Sudo::new(kind),
|
||||||
|
None if elevated => Sudo::new(SudoKind::Null),
|
||||||
|
None => Sudo::detect(),
|
||||||
|
};
|
||||||
|
debug!("Sudo: {:?}", sudo);
|
||||||
|
|
||||||
|
let (sudo, sudo_err) = match sudo {
|
||||||
|
Ok(sudo) => (Some(sudo), None),
|
||||||
|
Err(e) => (None, Some(e)),
|
||||||
|
};
|
||||||
|
|
||||||
#[cfg(target_os = "linux")]
|
#[cfg(target_os = "linux")]
|
||||||
let distribution = linux::Distribution::detect();
|
let distribution = linux::Distribution::detect();
|
||||||
|
|
||||||
let sudo = config.sudo_command().map_or_else(sudo::Sudo::detect, sudo::Sudo::new);
|
let run_type = execution_context::RunType::new(config.dry_run());
|
||||||
let run_type = executor::RunType::new(config.dry_run());
|
let ctx = execution_context::ExecutionContext::new(
|
||||||
let ctx = execution_context::ExecutionContext::new(run_type, sudo, &config);
|
run_type,
|
||||||
|
sudo,
|
||||||
|
&config,
|
||||||
|
#[cfg(target_os = "linux")]
|
||||||
|
&distribution,
|
||||||
|
);
|
||||||
let mut runner = runner::Runner::new(&ctx);
|
let mut runner = runner::Runner::new(&ctx);
|
||||||
|
|
||||||
// If
|
// If
|
||||||
//
|
//
|
||||||
// 1. the breaking changes notification shouldnot be skipped
|
// 1. the breaking changes notification shouldn't be skipped
|
||||||
// 2. this is the first execution of a major release
|
// 2. this is the first execution of a major release
|
||||||
//
|
//
|
||||||
// inform user of breaking changes
|
// inform user of breaking changes
|
||||||
if !should_skip() && first_run_of_major_release()? {
|
if !should_skip() && first_run_of_major_release()? {
|
||||||
print_breaking_changes();
|
print_breaking_changes();
|
||||||
|
|
||||||
if prompt_yesno("Confirmed?")? {
|
if prompt_yesno(&t!("Continue?"))? {
|
||||||
write_keep_file()?;
|
write_keep_file()?;
|
||||||
} else {
|
} else {
|
||||||
exit(1);
|
exit(1);
|
||||||
@@ -170,7 +197,7 @@ fn run() -> Result<()> {
|
|||||||
let should_self_update = env::var("TOPGRADE_NO_SELF_UPGRADE").is_err() && !config.no_self_update();
|
let should_self_update = env::var("TOPGRADE_NO_SELF_UPGRADE").is_err() && !config.no_self_update();
|
||||||
|
|
||||||
if should_self_update {
|
if should_self_update {
|
||||||
runner.execute(Step::SelfUpdate, "Self Update", || self_update::self_update(&ctx))?;
|
runner.execute(step::Step::SelfUpdate, "Self Update", || self_update::self_update(&ctx))?;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -193,310 +220,73 @@ fn run() -> Result<()> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(topgrades) = config.remote_topgrades() {
|
for step in step::default_steps() {
|
||||||
for remote_topgrade in topgrades.iter().filter(|t| config.should_execute_remote(hostname(), t)) {
|
step.run(&mut runner, &ctx)?
|
||||||
runner.execute(Step::Remotes, format!("Remote ({remote_topgrade})"), || {
|
|
||||||
ssh::ssh_step(&ctx, remote_topgrade)
|
|
||||||
})?;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(windows)]
|
let mut failed = false;
|
||||||
{
|
|
||||||
runner.execute(Step::Wsl, "WSL", || windows::run_wsl_topgrade(&ctx))?;
|
let report = runner.report();
|
||||||
runner.execute(Step::WslUpdate, "WSL", || windows::update_wsl(&ctx))?;
|
if !report.is_empty() {
|
||||||
runner.execute(Step::Chocolatey, "Chocolatey", || windows::run_chocolatey(&ctx))?;
|
print_separator(t!("Summary"));
|
||||||
runner.execute(Step::Scoop, "Scoop", || windows::run_scoop(&ctx))?;
|
|
||||||
runner.execute(Step::Winget, "Winget", || windows::run_winget(&ctx))?;
|
let mut skipped_missing_sudo = false;
|
||||||
runner.execute(Step::System, "Windows update", || windows::windows_update(&ctx))?;
|
|
||||||
runner.execute(Step::MicrosoftStore, "Microsoft Store", || {
|
for (key, result) in report {
|
||||||
windows::microsoft_store(&ctx)
|
if !failed && result.failed() {
|
||||||
})?;
|
failed = true;
|
||||||
|
}
|
||||||
|
if let StepResult::SkippedMissingSudo = result {
|
||||||
|
skipped_missing_sudo = true;
|
||||||
|
}
|
||||||
|
print_result(key, result);
|
||||||
|
}
|
||||||
|
|
||||||
|
if skipped_missing_sudo {
|
||||||
|
print_warning(t!(
|
||||||
|
"\nSome steps were skipped as sudo or equivalent could not be found."
|
||||||
|
));
|
||||||
|
// Steps can only fail with SkippedMissingSudo if sudo is None,
|
||||||
|
// therefore we must have a sudo_err
|
||||||
|
match sudo_err.unwrap() {
|
||||||
|
SudoCreateError::CannotFindBinary => {
|
||||||
|
#[cfg(unix)]
|
||||||
|
print_warning(t!(
|
||||||
|
"Install one of `sudo`, `doas`, `pkexec`, `run0` or `please` to run these steps."
|
||||||
|
));
|
||||||
|
|
||||||
|
// if this windows version supported Windows Sudo, the error would have been WinSudoDisabled
|
||||||
|
#[cfg(windows)]
|
||||||
|
print_warning(t!("Install gsudo to run these steps."));
|
||||||
|
}
|
||||||
|
#[cfg(windows)]
|
||||||
|
SudoCreateError::WinSudoDisabled => {
|
||||||
|
print_warning(t!(
|
||||||
|
"Install gsudo or enable Windows Sudo to run these steps.\nFor Windows Sudo, the default 'In a new window' mode is not supported as it prevents Topgrade from waiting for commands to finish. Please configure it to use 'Inline' mode instead.\nGo to https://go.microsoft.com/fwlink/?linkid=2257346 to learn more."
|
||||||
|
));
|
||||||
|
}
|
||||||
|
#[cfg(windows)]
|
||||||
|
SudoCreateError::WinSudoNewWindowMode => {
|
||||||
|
print_warning(t!(
|
||||||
|
"Windows Sudo was found, but it is set to 'In a new window' mode, which prevents Topgrade from waiting for commands to finish. Please configure it to use 'Inline' mode instead.\nGo to https://go.microsoft.com/fwlink/?linkid=2257346 to learn more."
|
||||||
|
));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(target_os = "linux")]
|
#[cfg(target_os = "linux")]
|
||||||
{
|
{
|
||||||
// NOTE: Due to breaking `nu` updates, `packer.nu` needs to be updated before `nu` get updated
|
if let Ok(distribution) = &distribution {
|
||||||
// by other package managers.
|
distribution.show_summary();
|
||||||
runner.execute(Step::Shell, "packer.nu", || linux::run_packer_nu(&ctx))?;
|
|
||||||
|
|
||||||
match &distribution {
|
|
||||||
Ok(distribution) => {
|
|
||||||
runner.execute(Step::System, "System update", || distribution.upgrade(&ctx))?;
|
|
||||||
}
|
|
||||||
Err(e) => {
|
|
||||||
println!("{}", t!("Error detecting current distribution: {error}", error = e));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
runner.execute(Step::ConfigUpdate, "config-update", || linux::run_config_update(&ctx))?;
|
|
||||||
|
|
||||||
runner.execute(Step::AM, "am", || linux::run_am(&ctx))?;
|
|
||||||
runner.execute(Step::AppMan, "appman", || linux::run_appman(&ctx))?;
|
|
||||||
runner.execute(Step::DebGet, "deb-get", || linux::run_deb_get(&ctx))?;
|
|
||||||
runner.execute(Step::Toolbx, "toolbx", || toolbx::run_toolbx(&ctx))?;
|
|
||||||
runner.execute(Step::Snap, "snap", || linux::run_snap(&ctx))?;
|
|
||||||
runner.execute(Step::Pacstall, "pacstall", || linux::run_pacstall(&ctx))?;
|
|
||||||
runner.execute(Step::Pacdef, "pacdef", || linux::run_pacdef(&ctx))?;
|
|
||||||
runner.execute(Step::Protonup, "protonup", || linux::run_protonup_update(&ctx))?;
|
|
||||||
runner.execute(Step::Distrobox, "distrobox", || linux::run_distrobox_update(&ctx))?;
|
|
||||||
runner.execute(Step::DkpPacman, "dkp-pacman", || linux::run_dkp_pacman_update(&ctx))?;
|
|
||||||
runner.execute(Step::System, "pihole", || linux::run_pihole_update(&ctx))?;
|
|
||||||
runner.execute(Step::Firmware, "Firmware upgrades", || linux::run_fwupdmgr(&ctx))?;
|
|
||||||
runner.execute(Step::Restarts, "Restarts", || linux::run_needrestart(&ctx))?;
|
|
||||||
|
|
||||||
runner.execute(Step::Flatpak, "Flatpak", || linux::run_flatpak(&ctx))?;
|
|
||||||
runner.execute(Step::BrewFormula, "Brew", || {
|
|
||||||
unix::run_brew_formula(&ctx, unix::BrewVariant::Path)
|
|
||||||
})?;
|
|
||||||
runner.execute(Step::Lure, "LURE", || linux::run_lure_update(&ctx))?;
|
|
||||||
runner.execute(Step::Waydroid, "Waydroid", || linux::run_waydroid(&ctx))?;
|
|
||||||
runner.execute(Step::AutoCpufreq, "auto-cpufreq", || linux::run_auto_cpufreq(&ctx))?;
|
|
||||||
runner.execute(Step::CinnamonSpices, "Cinnamon spices", || {
|
|
||||||
linux::run_cinnamon_spices_updater(&ctx)
|
|
||||||
})?;
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(target_os = "macos")]
|
|
||||||
{
|
|
||||||
runner.execute(Step::BrewFormula, "Brew (ARM)", || {
|
|
||||||
unix::run_brew_formula(&ctx, unix::BrewVariant::MacArm)
|
|
||||||
})?;
|
|
||||||
runner.execute(Step::BrewFormula, "Brew (Intel)", || {
|
|
||||||
unix::run_brew_formula(&ctx, unix::BrewVariant::MacIntel)
|
|
||||||
})?;
|
|
||||||
runner.execute(Step::BrewFormula, "Brew", || {
|
|
||||||
unix::run_brew_formula(&ctx, unix::BrewVariant::Path)
|
|
||||||
})?;
|
|
||||||
runner.execute(Step::BrewCask, "Brew Cask (ARM)", || {
|
|
||||||
unix::run_brew_cask(&ctx, unix::BrewVariant::MacArm)
|
|
||||||
})?;
|
|
||||||
runner.execute(Step::BrewCask, "Brew Cask (Intel)", || {
|
|
||||||
unix::run_brew_cask(&ctx, unix::BrewVariant::MacIntel)
|
|
||||||
})?;
|
|
||||||
runner.execute(Step::BrewCask, "Brew Cask", || {
|
|
||||||
unix::run_brew_cask(&ctx, unix::BrewVariant::Path)
|
|
||||||
})?;
|
|
||||||
runner.execute(Step::Macports, "MacPorts", || macos::run_macports(&ctx))?;
|
|
||||||
runner.execute(Step::Xcodes, "Xcodes", || macos::update_xcodes(&ctx))?;
|
|
||||||
runner.execute(Step::Sparkle, "Sparkle", || macos::run_sparkle(&ctx))?;
|
|
||||||
runner.execute(Step::Mas, "App Store", || macos::run_mas(&ctx))?;
|
|
||||||
runner.execute(Step::System, "System upgrade", || macos::upgrade_macos(&ctx))?;
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(target_os = "dragonfly")]
|
|
||||||
{
|
|
||||||
runner.execute(Step::Pkg, "DragonFly BSD Packages", || {
|
|
||||||
dragonfly::upgrade_packages(&ctx)
|
|
||||||
})?;
|
|
||||||
runner.execute(Step::Audit, "DragonFly Audit", || dragonfly::audit_packages(&ctx))?;
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(target_os = "freebsd")]
|
|
||||||
{
|
|
||||||
runner.execute(Step::Pkg, "FreeBSD Packages", || freebsd::upgrade_packages(&ctx))?;
|
|
||||||
runner.execute(Step::System, "FreeBSD Upgrade", || freebsd::upgrade_freebsd(&ctx))?;
|
|
||||||
runner.execute(Step::Audit, "FreeBSD Audit", || freebsd::audit_packages(&ctx))?;
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(target_os = "openbsd")]
|
|
||||||
{
|
|
||||||
runner.execute(Step::Pkg, "OpenBSD Packages", || openbsd::upgrade_packages(&ctx))?;
|
|
||||||
runner.execute(Step::System, "OpenBSD Upgrade", || openbsd::upgrade_openbsd(&ctx))?;
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(target_os = "android")]
|
|
||||||
{
|
|
||||||
runner.execute(Step::Pkg, "Termux Packages", || android::upgrade_packages(&ctx))?;
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(unix)]
|
|
||||||
{
|
|
||||||
runner.execute(Step::Yadm, "yadm", || unix::run_yadm(&ctx))?;
|
|
||||||
runner.execute(Step::Nix, "nix", || unix::run_nix(&ctx))?;
|
|
||||||
runner.execute(Step::Nix, "nix upgrade-nix", || unix::run_nix_self_upgrade(&ctx))?;
|
|
||||||
runner.execute(Step::Guix, "guix", || unix::run_guix(&ctx))?;
|
|
||||||
runner.execute(Step::HomeManager, "home-manager", || unix::run_home_manager(&ctx))?;
|
|
||||||
runner.execute(Step::Asdf, "asdf", || unix::run_asdf(&ctx))?;
|
|
||||||
runner.execute(Step::Mise, "mise", || unix::run_mise(&ctx))?;
|
|
||||||
runner.execute(Step::Pkgin, "pkgin", || unix::run_pkgin(&ctx))?;
|
|
||||||
runner.execute(Step::BunPackages, "bun-packages", || unix::run_bun_packages(&ctx))?;
|
|
||||||
runner.execute(Step::Shell, "zr", || zsh::run_zr(&ctx))?;
|
|
||||||
runner.execute(Step::Shell, "antibody", || zsh::run_antibody(&ctx))?;
|
|
||||||
runner.execute(Step::Shell, "antidote", || zsh::run_antidote(&ctx))?;
|
|
||||||
runner.execute(Step::Shell, "antigen", || zsh::run_antigen(&ctx))?;
|
|
||||||
runner.execute(Step::Shell, "zgenom", || zsh::run_zgenom(&ctx))?;
|
|
||||||
runner.execute(Step::Shell, "zplug", || zsh::run_zplug(&ctx))?;
|
|
||||||
runner.execute(Step::Shell, "zinit", || zsh::run_zinit(&ctx))?;
|
|
||||||
runner.execute(Step::Shell, "zi", || zsh::run_zi(&ctx))?;
|
|
||||||
runner.execute(Step::Shell, "zim", || zsh::run_zim(&ctx))?;
|
|
||||||
runner.execute(Step::Shell, "oh-my-zsh", || zsh::run_oh_my_zsh(&ctx))?;
|
|
||||||
runner.execute(Step::Shell, "oh-my-bash", || unix::run_oh_my_bash(&ctx))?;
|
|
||||||
runner.execute(Step::Shell, "fisher", || unix::run_fisher(&ctx))?;
|
|
||||||
runner.execute(Step::Shell, "bash-it", || unix::run_bashit(&ctx))?;
|
|
||||||
runner.execute(Step::Shell, "oh-my-fish", || unix::run_oh_my_fish(&ctx))?;
|
|
||||||
runner.execute(Step::Shell, "fish-plug", || unix::run_fish_plug(&ctx))?;
|
|
||||||
runner.execute(Step::Shell, "fundle", || unix::run_fundle(&ctx))?;
|
|
||||||
runner.execute(Step::Tmux, "tmux", || tmux::run_tpm(&ctx))?;
|
|
||||||
runner.execute(Step::Tldr, "TLDR", || unix::run_tldr(&ctx))?;
|
|
||||||
runner.execute(Step::Pearl, "pearl", || unix::run_pearl(&ctx))?;
|
|
||||||
#[cfg(not(any(target_os = "macos", target_os = "android")))]
|
|
||||||
runner.execute(Step::GnomeShellExtensions, "Gnome Shell Extensions", || {
|
|
||||||
unix::upgrade_gnome_extensions(&ctx)
|
|
||||||
})?;
|
|
||||||
runner.execute(Step::Pyenv, "pyenv", || unix::run_pyenv(&ctx))?;
|
|
||||||
runner.execute(Step::Sdkman, "SDKMAN!", || unix::run_sdkman(&ctx))?;
|
|
||||||
runner.execute(Step::Rcm, "rcm", || unix::run_rcm(&ctx))?;
|
|
||||||
runner.execute(Step::Maza, "maza", || unix::run_maza(&ctx))?;
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(not(any(
|
|
||||||
target_os = "freebsd",
|
|
||||||
target_os = "openbsd",
|
|
||||||
target_os = "netbsd",
|
|
||||||
target_os = "dragonfly"
|
|
||||||
)))]
|
|
||||||
{
|
|
||||||
runner.execute(Step::Atom, "apm", || generic::run_apm(&ctx))?;
|
|
||||||
}
|
|
||||||
|
|
||||||
// The following update function should be executed on all OSes.
|
|
||||||
runner.execute(Step::Fossil, "fossil", || generic::run_fossil(&ctx))?;
|
|
||||||
runner.execute(Step::Elan, "elan", || generic::run_elan(&ctx))?;
|
|
||||||
runner.execute(Step::Rye, "rye", || generic::run_rye(&ctx))?;
|
|
||||||
runner.execute(Step::Rustup, "rustup", || generic::run_rustup(&ctx))?;
|
|
||||||
runner.execute(Step::Juliaup, "juliaup", || generic::run_juliaup(&ctx))?;
|
|
||||||
runner.execute(Step::Dotnet, ".NET", || generic::run_dotnet_upgrade(&ctx))?;
|
|
||||||
runner.execute(Step::Choosenim, "choosenim", || generic::run_choosenim(&ctx))?;
|
|
||||||
runner.execute(Step::Cargo, "cargo", || generic::run_cargo_update(&ctx))?;
|
|
||||||
runner.execute(Step::Flutter, "Flutter", || generic::run_flutter_upgrade(&ctx))?;
|
|
||||||
runner.execute(Step::Go, "go-global-update", || go::run_go_global_update(&ctx))?;
|
|
||||||
runner.execute(Step::Go, "gup", || go::run_go_gup(&ctx))?;
|
|
||||||
runner.execute(Step::Emacs, "Emacs", || emacs.upgrade(&ctx))?;
|
|
||||||
runner.execute(Step::Opam, "opam", || generic::run_opam_update(&ctx))?;
|
|
||||||
runner.execute(Step::Vcpkg, "vcpkg", || generic::run_vcpkg_update(&ctx))?;
|
|
||||||
runner.execute(Step::Pipx, "pipx", || generic::run_pipx_update(&ctx))?;
|
|
||||||
runner.execute(Step::Pipxu, "pipxu", || generic::run_pipxu_update(&ctx))?;
|
|
||||||
runner.execute(Step::Vscode, "Visual Studio Code extensions", || {
|
|
||||||
generic::run_vscode_extensions_update(&ctx)
|
|
||||||
})?;
|
|
||||||
runner.execute(Step::Vscodium, "VSCodium extensions", || {
|
|
||||||
generic::run_vscodium_extensions_update(&ctx)
|
|
||||||
})?;
|
|
||||||
runner.execute(Step::Conda, "conda", || generic::run_conda_update(&ctx))?;
|
|
||||||
runner.execute(Step::Mamba, "mamba", || generic::run_mamba_update(&ctx))?;
|
|
||||||
runner.execute(Step::Pixi, "pixi", || generic::run_pixi_update(&ctx))?;
|
|
||||||
runner.execute(Step::Miktex, "miktex", || generic::run_miktex_packages_update(&ctx))?;
|
|
||||||
runner.execute(Step::Pip3, "pip3", || generic::run_pip3_update(&ctx))?;
|
|
||||||
runner.execute(Step::PipReview, "pip-review", || generic::run_pip_review_update(&ctx))?;
|
|
||||||
runner.execute(Step::PipReviewLocal, "pip-review (local)", || {
|
|
||||||
generic::run_pip_review_local_update(&ctx)
|
|
||||||
})?;
|
|
||||||
runner.execute(Step::Pipupgrade, "pipupgrade", || generic::run_pipupgrade_update(&ctx))?;
|
|
||||||
runner.execute(Step::Ghcup, "ghcup", || generic::run_ghcup_update(&ctx))?;
|
|
||||||
runner.execute(Step::Stack, "stack", || generic::run_stack_update(&ctx))?;
|
|
||||||
runner.execute(Step::Tlmgr, "tlmgr", || generic::run_tlmgr_update(&ctx))?;
|
|
||||||
runner.execute(Step::Myrepos, "myrepos", || generic::run_myrepos_update(&ctx))?;
|
|
||||||
runner.execute(Step::Chezmoi, "chezmoi", || generic::run_chezmoi_update(&ctx))?;
|
|
||||||
runner.execute(Step::Jetpack, "jetpack", || generic::run_jetpack(&ctx))?;
|
|
||||||
runner.execute(Step::Vim, "vim", || vim::upgrade_vim(&ctx))?;
|
|
||||||
runner.execute(Step::Vim, "Neovim", || vim::upgrade_neovim(&ctx))?;
|
|
||||||
runner.execute(Step::Vim, "The Ultimate vimrc", || vim::upgrade_ultimate_vimrc(&ctx))?;
|
|
||||||
runner.execute(Step::Vim, "voom", || vim::run_voom(&ctx))?;
|
|
||||||
runner.execute(Step::Kakoune, "Kakoune", || kakoune::upgrade_kak_plug(&ctx))?;
|
|
||||||
runner.execute(Step::Helix, "helix", || generic::run_helix_grammars(&ctx))?;
|
|
||||||
runner.execute(Step::Node, "npm", || node::run_npm_upgrade(&ctx))?;
|
|
||||||
runner.execute(Step::Yarn, "yarn", || node::run_yarn_upgrade(&ctx))?;
|
|
||||||
runner.execute(Step::Pnpm, "pnpm", || node::run_pnpm_upgrade(&ctx))?;
|
|
||||||
runner.execute(Step::VoltaPackages, "volta packages", || {
|
|
||||||
node::run_volta_packages_upgrade(&ctx)
|
|
||||||
})?;
|
|
||||||
runner.execute(Step::Containers, "Containers", || containers::run_containers(&ctx))?;
|
|
||||||
runner.execute(Step::Deno, "deno", || node::deno_upgrade(&ctx))?;
|
|
||||||
runner.execute(Step::Composer, "composer", || generic::run_composer_update(&ctx))?;
|
|
||||||
runner.execute(Step::Krew, "krew", || generic::run_krew_upgrade(&ctx))?;
|
|
||||||
runner.execute(Step::Helm, "helm", || generic::run_helm_repo_update(&ctx))?;
|
|
||||||
runner.execute(Step::Gem, "gem", || generic::run_gem(&ctx))?;
|
|
||||||
runner.execute(Step::RubyGems, "rubygems", || generic::run_rubygems(&ctx))?;
|
|
||||||
runner.execute(Step::Julia, "julia", || generic::update_julia_packages(&ctx))?;
|
|
||||||
runner.execute(Step::Haxelib, "haxelib", || generic::run_haxelib_update(&ctx))?;
|
|
||||||
runner.execute(Step::Sheldon, "sheldon", || generic::run_sheldon(&ctx))?;
|
|
||||||
runner.execute(Step::Stew, "stew", || generic::run_stew(&ctx))?;
|
|
||||||
runner.execute(Step::Rtcl, "rtcl", || generic::run_rtcl(&ctx))?;
|
|
||||||
runner.execute(Step::Bin, "bin", || generic::bin_update(&ctx))?;
|
|
||||||
runner.execute(Step::Gcloud, "gcloud", || generic::run_gcloud_components_update(&ctx))?;
|
|
||||||
runner.execute(Step::Micro, "micro", || generic::run_micro(&ctx))?;
|
|
||||||
runner.execute(Step::Raco, "raco", || generic::run_raco_update(&ctx))?;
|
|
||||||
runner.execute(Step::Spicetify, "spicetify", || generic::spicetify_upgrade(&ctx))?;
|
|
||||||
runner.execute(Step::GithubCliExtensions, "GitHub CLI Extensions", || {
|
|
||||||
generic::run_ghcli_extensions_upgrade(&ctx)
|
|
||||||
})?;
|
|
||||||
runner.execute(Step::Bob, "Bob", || generic::run_bob(&ctx))?;
|
|
||||||
runner.execute(Step::Certbot, "Certbot", || generic::run_certbot(&ctx))?;
|
|
||||||
runner.execute(Step::GitRepos, "Git Repositories", || git::run_git_pull(&ctx))?;
|
|
||||||
runner.execute(Step::ClamAvDb, "ClamAV Databases", || generic::run_freshclam(&ctx))?;
|
|
||||||
runner.execute(Step::PlatformioCore, "PlatformIO Core", || {
|
|
||||||
generic::run_platform_io(&ctx)
|
|
||||||
})?;
|
|
||||||
runner.execute(Step::Lensfun, "Lensfun's database update", || {
|
|
||||||
generic::run_lensfun_update_data(&ctx)
|
|
||||||
})?;
|
|
||||||
runner.execute(Step::Poetry, "Poetry", || generic::run_poetry(&ctx))?;
|
|
||||||
runner.execute(Step::Uv, "uv", || generic::run_uv(&ctx))?;
|
|
||||||
runner.execute(Step::Zvm, "ZVM", || generic::run_zvm(&ctx))?;
|
|
||||||
runner.execute(Step::Aqua, "aqua", || generic::run_aqua(&ctx))?;
|
|
||||||
runner.execute(Step::Bun, "bun", || generic::run_bun(&ctx))?;
|
|
||||||
runner.execute(Step::Zigup, "zigup", || generic::run_zigup(&ctx))?;
|
|
||||||
runner.execute(Step::JetBrainsToolbox, "JetBrains Toolbox", || {
|
|
||||||
generic::run_jetbrains_toolbox(&ctx)
|
|
||||||
})?;
|
|
||||||
|
|
||||||
if should_run_powershell {
|
|
||||||
runner.execute(Step::Powershell, "Powershell Modules Update", || {
|
|
||||||
powershell.update_modules(&ctx)
|
|
||||||
})?;
|
|
||||||
}
|
|
||||||
|
|
||||||
if let Some(commands) = config.commands() {
|
|
||||||
for (name, command) in commands {
|
|
||||||
if config.should_run_custom_command(name) {
|
|
||||||
runner.execute(Step::CustomCommands, name, || {
|
|
||||||
generic::run_custom_command(name, command, &ctx)
|
|
||||||
})?;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if config.should_run(Step::Vagrant) {
|
|
||||||
if let Ok(boxes) = vagrant::collect_boxes(&ctx) {
|
|
||||||
for vagrant_box in boxes {
|
|
||||||
runner.execute(Step::Vagrant, format!("Vagrant ({})", vagrant_box.smart_name()), || {
|
|
||||||
vagrant::topgrade_vagrant_box(&ctx, &vagrant_box)
|
|
||||||
})?;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
runner.execute(Step::Vagrant, "Vagrant boxes", || vagrant::upgrade_vagrant_boxes(&ctx))?;
|
|
||||||
|
|
||||||
if !runner.report().data().is_empty() {
|
|
||||||
print_separator(t!("Summary"));
|
|
||||||
|
|
||||||
for (key, result) in runner.report().data() {
|
|
||||||
print_result(key, result);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(target_os = "linux")]
|
|
||||||
{
|
|
||||||
if let Ok(distribution) = &distribution {
|
|
||||||
distribution.show_summary();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
let mut post_command_failed = false;
|
|
||||||
if let Some(commands) = config.post_commands() {
|
if let Some(commands) = config.post_commands() {
|
||||||
for (name, command) in commands {
|
for (name, command) in commands {
|
||||||
if generic::run_custom_command(name, command, &ctx).is_err() {
|
let result = generic::run_custom_command(name, command, &ctx);
|
||||||
post_command_failed = true;
|
if !failed && result.is_err() {
|
||||||
|
failed = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -509,7 +299,8 @@ fn run() -> Result<()> {
|
|||||||
run_shell().context("Failed to execute shell")?;
|
run_shell().context("Failed to execute shell")?;
|
||||||
}
|
}
|
||||||
Ok(Key::Char('r' | 'R')) => {
|
Ok(Key::Char('r' | 'R')) => {
|
||||||
reboot().context("Failed to reboot")?;
|
println!("{}", t!("Rebooting..."));
|
||||||
|
reboot(&ctx).context("Failed to reboot")?;
|
||||||
}
|
}
|
||||||
Ok(Key::Char('q' | 'Q')) => (),
|
Ok(Key::Char('q' | 'Q')) => (),
|
||||||
_ => {
|
_ => {
|
||||||
@@ -520,8 +311,6 @@ fn run() -> Result<()> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let failed = post_command_failed || runner.report().data().iter().any(|(_, result)| result.failed());
|
|
||||||
|
|
||||||
if !config.skip_notify() {
|
if !config.skip_notify() {
|
||||||
notify_desktop(
|
notify_desktop(
|
||||||
if failed {
|
if failed {
|
||||||
|
|||||||
@@ -1,45 +0,0 @@
|
|||||||
use std::borrow::Cow;
|
|
||||||
|
|
||||||
pub enum StepResult {
|
|
||||||
Success,
|
|
||||||
Failure,
|
|
||||||
Ignored,
|
|
||||||
Skipped(String),
|
|
||||||
}
|
|
||||||
|
|
||||||
impl StepResult {
|
|
||||||
pub fn failed(&self) -> bool {
|
|
||||||
match self {
|
|
||||||
StepResult::Success | StepResult::Ignored | StepResult::Skipped(_) => false,
|
|
||||||
StepResult::Failure => true,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
type CowString<'a> = Cow<'a, str>;
|
|
||||||
type ReportData<'a> = Vec<(CowString<'a>, StepResult)>;
|
|
||||||
pub struct Report<'a> {
|
|
||||||
data: ReportData<'a>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a> Report<'a> {
|
|
||||||
pub fn new() -> Self {
|
|
||||||
Self { data: Vec::new() }
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn push_result<M>(&mut self, result: Option<(M, StepResult)>)
|
|
||||||
where
|
|
||||||
M: Into<CowString<'a>>,
|
|
||||||
{
|
|
||||||
if let Some((key, success)) = result {
|
|
||||||
let key = key.into();
|
|
||||||
|
|
||||||
debug_assert!(!self.data.iter().any(|(k, _)| k == &key), "{key} already reported");
|
|
||||||
self.data.push((key, success));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn data(&self) -> &ReportData<'a> {
|
|
||||||
&self.data
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,14 +1,36 @@
|
|||||||
use crate::ctrlc;
|
|
||||||
use crate::error::{DryRun, SkipStep};
|
|
||||||
use crate::execution_context::ExecutionContext;
|
|
||||||
use crate::report::{Report, StepResult};
|
|
||||||
use crate::terminal::print_error;
|
|
||||||
use crate::{config::Step, terminal::should_retry};
|
|
||||||
use color_eyre::eyre::Result;
|
use color_eyre::eyre::Result;
|
||||||
|
use rust_i18n::t;
|
||||||
use std::borrow::Cow;
|
use std::borrow::Cow;
|
||||||
use std::fmt::Debug;
|
use std::fmt::Debug;
|
||||||
use tracing::debug;
|
use tracing::debug;
|
||||||
|
|
||||||
|
use crate::ctrlc;
|
||||||
|
use crate::error::{DryRun, MissingSudo, SkipStep};
|
||||||
|
use crate::execution_context::ExecutionContext;
|
||||||
|
use crate::step::Step;
|
||||||
|
use crate::terminal::{print_error, print_warning, should_retry};
|
||||||
|
|
||||||
|
pub enum StepResult {
|
||||||
|
Success,
|
||||||
|
Failure,
|
||||||
|
Ignored,
|
||||||
|
SkippedMissingSudo,
|
||||||
|
Skipped(String),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl StepResult {
|
||||||
|
pub fn failed(&self) -> bool {
|
||||||
|
use StepResult::*;
|
||||||
|
|
||||||
|
match self {
|
||||||
|
Success | Ignored | Skipped(_) | SkippedMissingSudo => false,
|
||||||
|
Failure => true,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
type Report<'a> = Vec<(Cow<'a, str>, StepResult)>;
|
||||||
|
|
||||||
pub struct Runner<'a> {
|
pub struct Runner<'a> {
|
||||||
ctx: &'a ExecutionContext<'a>,
|
ctx: &'a ExecutionContext<'a>,
|
||||||
report: Report<'a>,
|
report: Report<'a>,
|
||||||
@@ -18,20 +40,25 @@ impl<'a> Runner<'a> {
|
|||||||
pub fn new(ctx: &'a ExecutionContext) -> Runner<'a> {
|
pub fn new(ctx: &'a ExecutionContext) -> Runner<'a> {
|
||||||
Runner {
|
Runner {
|
||||||
ctx,
|
ctx,
|
||||||
report: Report::new(),
|
report: Vec::new(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn execute<F, M>(&mut self, step: Step, key: M, func: F) -> Result<()>
|
fn push_result(&mut self, key: Cow<'a, str>, result: StepResult) {
|
||||||
|
debug_assert!(!self.report.iter().any(|(k, _)| k == &key), "{key} already reported");
|
||||||
|
self.report.push((key, result));
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn execute<K, F>(&mut self, step: Step, key: K, func: F) -> Result<()>
|
||||||
where
|
where
|
||||||
|
K: Into<Cow<'a, str>> + Debug,
|
||||||
F: Fn() -> Result<()>,
|
F: Fn() -> Result<()>,
|
||||||
M: Into<Cow<'a, str>> + Debug,
|
|
||||||
{
|
{
|
||||||
if !self.ctx.config().should_run(step) {
|
if !self.ctx.config().should_run(step) {
|
||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
|
|
||||||
let key = key.into();
|
let key: Cow<'a, str> = key.into();
|
||||||
debug!("Step {:?}", key);
|
debug!("Step {:?}", key);
|
||||||
|
|
||||||
// alter the `func` to put it in a span
|
// alter the `func` to put it in a span
|
||||||
@@ -45,13 +72,18 @@ impl<'a> Runner<'a> {
|
|||||||
loop {
|
loop {
|
||||||
match func() {
|
match func() {
|
||||||
Ok(()) => {
|
Ok(()) => {
|
||||||
self.report.push_result(Some((key, StepResult::Success)));
|
self.push_result(key, StepResult::Success);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
Err(e) if e.downcast_ref::<DryRun>().is_some() => break,
|
Err(e) if e.downcast_ref::<DryRun>().is_some() => break,
|
||||||
|
Err(e) if e.downcast_ref::<MissingSudo>().is_some() => {
|
||||||
|
print_warning(t!("Skipping step, sudo is required"));
|
||||||
|
self.push_result(key, StepResult::SkippedMissingSudo);
|
||||||
|
break;
|
||||||
|
}
|
||||||
Err(e) if e.downcast_ref::<SkipStep>().is_some() => {
|
Err(e) if e.downcast_ref::<SkipStep>().is_some() => {
|
||||||
if self.ctx.config().verbose() || self.ctx.config().show_skipped() {
|
if self.ctx.config().verbose() || self.ctx.config().show_skipped() {
|
||||||
self.report.push_result(Some((key, StepResult::Skipped(e.to_string()))));
|
self.push_result(key, StepResult::Skipped(e.to_string()));
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -72,14 +104,14 @@ impl<'a> Runner<'a> {
|
|||||||
};
|
};
|
||||||
|
|
||||||
if !should_retry {
|
if !should_retry {
|
||||||
self.report.push_result(Some((
|
self.push_result(
|
||||||
key,
|
key,
|
||||||
if ignore_failure {
|
if ignore_failure {
|
||||||
StepResult::Ignored
|
StepResult::Ignored
|
||||||
} else {
|
} else {
|
||||||
StepResult::Failure
|
StepResult::Failure
|
||||||
},
|
},
|
||||||
)));
|
);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -89,7 +121,7 @@ impl<'a> Runner<'a> {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn report(&self) -> &Report {
|
pub fn report(&self) -> &Report<'_> {
|
||||||
&self.report
|
&self.report
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ use std::env;
|
|||||||
use std::os::unix::process::CommandExt as _;
|
use std::os::unix::process::CommandExt as _;
|
||||||
use std::process::Command;
|
use std::process::Command;
|
||||||
|
|
||||||
use crate::config::Step;
|
use crate::step::Step;
|
||||||
use color_eyre::eyre::{bail, Result};
|
use color_eyre::eyre::{bail, Result};
|
||||||
use rust_i18n::t;
|
use rust_i18n::t;
|
||||||
use self_update_crate::backends::github::Update;
|
use self_update_crate::backends::github::Update;
|
||||||
|
|||||||
888
src/step.rs
Normal file
888
src/step.rs
Normal file
@@ -0,0 +1,888 @@
|
|||||||
|
use crate::execution_context::ExecutionContext;
|
||||||
|
use crate::runner::Runner;
|
||||||
|
use clap::ValueEnum;
|
||||||
|
use color_eyre::Result;
|
||||||
|
#[cfg(target_os = "linux")]
|
||||||
|
use rust_i18n::t;
|
||||||
|
use serde::Deserialize;
|
||||||
|
use strum::{EnumCount, EnumIter, EnumString, VariantNames};
|
||||||
|
|
||||||
|
#[cfg(feature = "self-update")]
|
||||||
|
use crate::self_update;
|
||||||
|
use crate::steps::remote::vagrant;
|
||||||
|
#[allow(clippy::wildcard_imports)]
|
||||||
|
use crate::steps::*;
|
||||||
|
use crate::utils::hostname;
|
||||||
|
|
||||||
|
#[derive(ValueEnum, EnumString, VariantNames, Debug, Clone, PartialEq, Eq, Deserialize, EnumIter, Copy, EnumCount)]
|
||||||
|
#[clap(rename_all = "snake_case")]
|
||||||
|
#[serde(rename_all = "snake_case")]
|
||||||
|
#[strum(serialize_all = "snake_case")]
|
||||||
|
pub enum Step {
|
||||||
|
AM,
|
||||||
|
AndroidStudio,
|
||||||
|
AppMan,
|
||||||
|
Aqua,
|
||||||
|
Asdf,
|
||||||
|
Atom,
|
||||||
|
Atuin,
|
||||||
|
Audit,
|
||||||
|
AutoCpufreq,
|
||||||
|
Bin,
|
||||||
|
Bob,
|
||||||
|
BrewCask,
|
||||||
|
BrewFormula,
|
||||||
|
Bun,
|
||||||
|
BunPackages,
|
||||||
|
Cargo,
|
||||||
|
Certbot,
|
||||||
|
Chezmoi,
|
||||||
|
Chocolatey,
|
||||||
|
Choosenim,
|
||||||
|
CinnamonSpices,
|
||||||
|
ClamAvDb,
|
||||||
|
Composer,
|
||||||
|
Conda,
|
||||||
|
ConfigUpdate,
|
||||||
|
Containers,
|
||||||
|
CustomCommands,
|
||||||
|
DebGet,
|
||||||
|
Deno,
|
||||||
|
Distrobox,
|
||||||
|
DkpPacman,
|
||||||
|
Dotnet,
|
||||||
|
Elan,
|
||||||
|
Emacs,
|
||||||
|
Firmware,
|
||||||
|
Flatpak,
|
||||||
|
Flutter,
|
||||||
|
Fossil,
|
||||||
|
Gcloud,
|
||||||
|
Gem,
|
||||||
|
Ghcup,
|
||||||
|
GitRepos,
|
||||||
|
GithubCliExtensions,
|
||||||
|
GnomeShellExtensions,
|
||||||
|
Go,
|
||||||
|
Guix,
|
||||||
|
Haxelib,
|
||||||
|
Helix,
|
||||||
|
Helm,
|
||||||
|
HomeManager,
|
||||||
|
// These names are miscapitalized on purpose, so the CLI name is
|
||||||
|
// `jetbrains_pycharm` instead of `jet_brains_py_charm`.
|
||||||
|
JetbrainsAqua,
|
||||||
|
JetbrainsClion,
|
||||||
|
JetbrainsDatagrip,
|
||||||
|
JetbrainsDataspell,
|
||||||
|
JetbrainsGateway,
|
||||||
|
JetbrainsGoland,
|
||||||
|
JetbrainsIdea,
|
||||||
|
JetbrainsMps,
|
||||||
|
JetbrainsPhpstorm,
|
||||||
|
JetbrainsPycharm,
|
||||||
|
JetbrainsRider,
|
||||||
|
JetbrainsRubymine,
|
||||||
|
JetbrainsRustrover,
|
||||||
|
JetbrainsToolbox,
|
||||||
|
JetbrainsWebstorm,
|
||||||
|
Jetpack,
|
||||||
|
Julia,
|
||||||
|
Juliaup,
|
||||||
|
Kakoune,
|
||||||
|
Krew,
|
||||||
|
Lensfun,
|
||||||
|
Lure,
|
||||||
|
Macports,
|
||||||
|
Mamba,
|
||||||
|
Mandb,
|
||||||
|
Mas,
|
||||||
|
Maza,
|
||||||
|
Micro,
|
||||||
|
MicrosoftStore,
|
||||||
|
Miktex,
|
||||||
|
Mise,
|
||||||
|
Myrepos,
|
||||||
|
Nix,
|
||||||
|
NixHelper,
|
||||||
|
Node,
|
||||||
|
Opam,
|
||||||
|
Pacdef,
|
||||||
|
Pacstall,
|
||||||
|
Pearl,
|
||||||
|
Pip3,
|
||||||
|
PipReview,
|
||||||
|
PipReviewLocal,
|
||||||
|
Pipupgrade,
|
||||||
|
Pipx,
|
||||||
|
Pipxu,
|
||||||
|
Pixi,
|
||||||
|
Pkg,
|
||||||
|
Pkgfile,
|
||||||
|
Pkgin,
|
||||||
|
PlatformioCore,
|
||||||
|
Pnpm,
|
||||||
|
Poetry,
|
||||||
|
Powershell,
|
||||||
|
Protonup,
|
||||||
|
Pyenv,
|
||||||
|
Raco,
|
||||||
|
Rcm,
|
||||||
|
Remotes,
|
||||||
|
Restarts,
|
||||||
|
Rtcl,
|
||||||
|
RubyGems,
|
||||||
|
Rustup,
|
||||||
|
Rye,
|
||||||
|
Scoop,
|
||||||
|
Sdkman,
|
||||||
|
SelfUpdate,
|
||||||
|
Sheldon,
|
||||||
|
Shell,
|
||||||
|
Snap,
|
||||||
|
Sparkle,
|
||||||
|
Spicetify,
|
||||||
|
Stack,
|
||||||
|
Stew,
|
||||||
|
System,
|
||||||
|
Tldr,
|
||||||
|
Tlmgr,
|
||||||
|
Tmux,
|
||||||
|
Toolbx,
|
||||||
|
Typst,
|
||||||
|
Uv,
|
||||||
|
Vagrant,
|
||||||
|
Vcpkg,
|
||||||
|
Vim,
|
||||||
|
VoltaPackages,
|
||||||
|
Vscode,
|
||||||
|
VscodeInsiders,
|
||||||
|
Vscodium,
|
||||||
|
VscodiumInsiders,
|
||||||
|
Waydroid,
|
||||||
|
Winget,
|
||||||
|
Wsl,
|
||||||
|
WslUpdate,
|
||||||
|
Xcodes,
|
||||||
|
Yadm,
|
||||||
|
Yarn,
|
||||||
|
Yazi,
|
||||||
|
Zigup,
|
||||||
|
Zvm,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Step {
|
||||||
|
#[allow(clippy::too_many_lines)]
|
||||||
|
pub fn run(&self, runner: &mut Runner, ctx: &ExecutionContext) -> Result<()> {
|
||||||
|
use Step::*;
|
||||||
|
|
||||||
|
match *self {
|
||||||
|
AM =>
|
||||||
|
{
|
||||||
|
#[cfg(target_os = "linux")]
|
||||||
|
runner.execute(*self, "am", || linux::run_am(ctx))?
|
||||||
|
}
|
||||||
|
AndroidStudio => runner.execute(*self, "Android Studio Plugins", || generic::run_android_studio(ctx))?,
|
||||||
|
AppMan =>
|
||||||
|
{
|
||||||
|
#[cfg(target_os = "linux")]
|
||||||
|
runner.execute(*self, "appman", || linux::run_appman(ctx))?
|
||||||
|
}
|
||||||
|
Aqua => runner.execute(*self, "aqua", || generic::run_aqua(ctx))?,
|
||||||
|
Asdf =>
|
||||||
|
{
|
||||||
|
#[cfg(unix)]
|
||||||
|
runner.execute(*self, "asdf", || unix::run_asdf(ctx))?
|
||||||
|
}
|
||||||
|
Atom =>
|
||||||
|
{
|
||||||
|
#[cfg(not(any(
|
||||||
|
target_os = "freebsd",
|
||||||
|
target_os = "openbsd",
|
||||||
|
target_os = "netbsd",
|
||||||
|
target_os = "dragonfly"
|
||||||
|
)))]
|
||||||
|
runner.execute(*self, "apm", || generic::run_apm(ctx))?
|
||||||
|
}
|
||||||
|
Atuin =>
|
||||||
|
{
|
||||||
|
#[cfg(unix)]
|
||||||
|
runner.execute(*self, "atuin", || unix::run_atuin(ctx))?
|
||||||
|
}
|
||||||
|
Audit => {
|
||||||
|
#[cfg(target_os = "dragonfly")]
|
||||||
|
runner.execute(*self, "DragonFly Audit", || dragonfly::audit_packages(ctx))?;
|
||||||
|
#[cfg(target_os = "freebsd")]
|
||||||
|
runner.execute(*self, "FreeBSD Audit", || freebsd::audit_packages(ctx))?
|
||||||
|
}
|
||||||
|
AutoCpufreq =>
|
||||||
|
{
|
||||||
|
#[cfg(target_os = "linux")]
|
||||||
|
runner.execute(*self, "auto-cpufreq", || linux::run_auto_cpufreq(ctx))?
|
||||||
|
}
|
||||||
|
Bin => runner.execute(*self, "bin", || generic::bin_update(ctx))?,
|
||||||
|
Bob => runner.execute(*self, "Bob", || generic::run_bob(ctx))?,
|
||||||
|
BrewCask => {
|
||||||
|
#[cfg(target_os = "macos")]
|
||||||
|
runner.execute(*self, "Brew Cask", || unix::run_brew_cask(ctx, unix::BrewVariant::Path))?;
|
||||||
|
#[cfg(target_os = "macos")]
|
||||||
|
runner.execute(*self, "Brew Cask (Intel)", || {
|
||||||
|
unix::run_brew_cask(ctx, unix::BrewVariant::MacIntel)
|
||||||
|
})?;
|
||||||
|
#[cfg(target_os = "macos")]
|
||||||
|
runner.execute(*self, "Brew Cask (ARM)", || {
|
||||||
|
unix::run_brew_cask(ctx, unix::BrewVariant::MacArm)
|
||||||
|
})?
|
||||||
|
}
|
||||||
|
BrewFormula => {
|
||||||
|
#[cfg(target_os = "linux")]
|
||||||
|
runner.execute(*self, "Brew", || unix::run_brew_formula(ctx, unix::BrewVariant::Path))?;
|
||||||
|
#[cfg(target_os = "macos")]
|
||||||
|
runner.execute(*self, "Brew (ARM)", || {
|
||||||
|
unix::run_brew_formula(ctx, unix::BrewVariant::MacArm)
|
||||||
|
})?;
|
||||||
|
#[cfg(target_os = "macos")]
|
||||||
|
runner.execute(*self, "Brew (Intel)", || {
|
||||||
|
unix::run_brew_formula(ctx, unix::BrewVariant::MacIntel)
|
||||||
|
})?
|
||||||
|
}
|
||||||
|
Bun => runner.execute(*self, "bun", || generic::run_bun(ctx))?,
|
||||||
|
BunPackages =>
|
||||||
|
{
|
||||||
|
#[cfg(unix)]
|
||||||
|
runner.execute(*self, "bun-packages", || unix::run_bun_packages(ctx))?
|
||||||
|
}
|
||||||
|
Cargo => runner.execute(*self, "cargo", || generic::run_cargo_update(ctx))?,
|
||||||
|
Certbot => runner.execute(*self, "Certbot", || generic::run_certbot(ctx))?,
|
||||||
|
Chezmoi => runner.execute(*self, "chezmoi", || generic::run_chezmoi_update(ctx))?,
|
||||||
|
Chocolatey =>
|
||||||
|
{
|
||||||
|
#[cfg(windows)]
|
||||||
|
runner.execute(*self, "Chocolatey", || windows::run_chocolatey(ctx))?
|
||||||
|
}
|
||||||
|
Choosenim => runner.execute(*self, "choosenim", || generic::run_choosenim(ctx))?,
|
||||||
|
CinnamonSpices =>
|
||||||
|
{
|
||||||
|
#[cfg(target_os = "linux")]
|
||||||
|
runner.execute(*self, "Cinnamon spices", || linux::run_cinnamon_spices_updater(ctx))?
|
||||||
|
}
|
||||||
|
ClamAvDb => runner.execute(*self, "ClamAV Databases", || generic::run_freshclam(ctx))?,
|
||||||
|
Composer => runner.execute(*self, "composer", || generic::run_composer_update(ctx))?,
|
||||||
|
Conda => runner.execute(*self, "conda", || generic::run_conda_update(ctx))?,
|
||||||
|
ConfigUpdate =>
|
||||||
|
{
|
||||||
|
#[cfg(target_os = "linux")]
|
||||||
|
runner.execute(*self, "config-update", || linux::run_config_update(ctx))?
|
||||||
|
}
|
||||||
|
Containers => runner.execute(*self, "Containers", || containers::run_containers(ctx))?,
|
||||||
|
CustomCommands => {
|
||||||
|
if let Some(commands) = ctx.config().commands() {
|
||||||
|
for (name, command) in commands
|
||||||
|
.iter()
|
||||||
|
.filter(|(n, _)| ctx.config().should_run_custom_command(n))
|
||||||
|
{
|
||||||
|
runner.execute(*self, name.clone(), || generic::run_custom_command(name, command, ctx))?;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
DebGet =>
|
||||||
|
{
|
||||||
|
#[cfg(target_os = "linux")]
|
||||||
|
runner.execute(*self, "deb-get", || linux::run_deb_get(ctx))?
|
||||||
|
}
|
||||||
|
Deno => runner.execute(*self, "deno", || node::deno_upgrade(ctx))?,
|
||||||
|
Distrobox =>
|
||||||
|
{
|
||||||
|
#[cfg(target_os = "linux")]
|
||||||
|
runner.execute(*self, "distrobox", || linux::run_distrobox_update(ctx))?
|
||||||
|
}
|
||||||
|
DkpPacman =>
|
||||||
|
{
|
||||||
|
#[cfg(target_os = "linux")]
|
||||||
|
runner.execute(*self, "dkp-pacman", || linux::run_dkp_pacman_update(ctx))?
|
||||||
|
}
|
||||||
|
Dotnet => runner.execute(*self, ".NET", || generic::run_dotnet_upgrade(ctx))?,
|
||||||
|
Elan => runner.execute(*self, "elan", || generic::run_elan(ctx))?,
|
||||||
|
Emacs => runner.execute(*self, "Emacs", || emacs::Emacs::new().upgrade(ctx))?,
|
||||||
|
Firmware =>
|
||||||
|
{
|
||||||
|
#[cfg(target_os = "linux")]
|
||||||
|
runner.execute(*self, "Firmware", || linux::run_fwupdmgr(ctx))?
|
||||||
|
}
|
||||||
|
Flatpak =>
|
||||||
|
{
|
||||||
|
#[cfg(target_os = "linux")]
|
||||||
|
runner.execute(*self, "Flatpak", || linux::run_flatpak(ctx))?
|
||||||
|
}
|
||||||
|
Flutter => runner.execute(*self, "Flutter", || generic::run_flutter_upgrade(ctx))?,
|
||||||
|
Fossil => runner.execute(*self, "fossil", || generic::run_fossil(ctx))?,
|
||||||
|
Gcloud => runner.execute(*self, "gcloud", || generic::run_gcloud_components_update(ctx))?,
|
||||||
|
Gem => runner.execute(*self, "gem", || generic::run_gem(ctx))?,
|
||||||
|
Ghcup => runner.execute(*self, "ghcup", || generic::run_ghcup_update(ctx))?,
|
||||||
|
GitRepos => runner.execute(*self, "Git Repositories", || git::run_git_pull(ctx))?,
|
||||||
|
GithubCliExtensions => runner.execute(*self, "GitHub CLI Extensions", || {
|
||||||
|
generic::run_ghcli_extensions_upgrade(ctx)
|
||||||
|
})?,
|
||||||
|
GnomeShellExtensions =>
|
||||||
|
{
|
||||||
|
#[cfg(all(unix, not(any(target_os = "macos", target_os = "android"))))]
|
||||||
|
runner.execute(*self, "Gnome Shell Extensions", || unix::upgrade_gnome_extensions(ctx))?
|
||||||
|
}
|
||||||
|
Go => {
|
||||||
|
runner.execute(*self, "go-global-update", || go::run_go_global_update(ctx))?;
|
||||||
|
runner.execute(*self, "gup", || go::run_go_gup(ctx))?
|
||||||
|
}
|
||||||
|
Guix =>
|
||||||
|
{
|
||||||
|
#[cfg(unix)]
|
||||||
|
runner.execute(*self, "guix", || unix::run_guix(ctx))?
|
||||||
|
}
|
||||||
|
Haxelib => runner.execute(*self, "haxelib", || generic::run_haxelib_update(ctx))?,
|
||||||
|
Helix => runner.execute(*self, "helix", || generic::run_helix_grammars(ctx))?,
|
||||||
|
Helm => runner.execute(*self, "helm", || generic::run_helm_repo_update(ctx))?,
|
||||||
|
HomeManager =>
|
||||||
|
{
|
||||||
|
#[cfg(unix)]
|
||||||
|
runner.execute(*self, "home-manager", || unix::run_home_manager(ctx))?
|
||||||
|
}
|
||||||
|
JetbrainsAqua => runner.execute(*self, "JetBrains Aqua Plugins", || generic::run_jetbrains_aqua(ctx))?,
|
||||||
|
JetbrainsClion => runner.execute(*self, "JetBrains CL", || generic::run_jetbrains_clion(ctx))?,
|
||||||
|
JetbrainsDatagrip => {
|
||||||
|
runner.execute(*self, "JetBrains DataGrip", || generic::run_jetbrains_datagrip(ctx))?
|
||||||
|
}
|
||||||
|
JetbrainsDataspell => runner.execute(*self, "JetBrains DataSpell Plugins", || {
|
||||||
|
generic::run_jetbrains_dataspell(ctx)
|
||||||
|
})?,
|
||||||
|
JetbrainsGateway => runner.execute(*self, "JetBrains Gateway Plugins", || {
|
||||||
|
generic::run_jetbrains_gateway(ctx)
|
||||||
|
})?,
|
||||||
|
JetbrainsGoland => {
|
||||||
|
runner.execute(*self, "JetBrains GoLand Plugins", || generic::run_jetbrains_goland(ctx))?
|
||||||
|
}
|
||||||
|
JetbrainsIdea => runner.execute(*self, "JetBrains IntelliJ IDEA Plugins", || {
|
||||||
|
generic::run_jetbrains_idea(ctx)
|
||||||
|
})?,
|
||||||
|
JetbrainsMps => runner.execute(*self, "JetBrains MPS Plugins", || generic::run_jetbrains_mps(ctx))?,
|
||||||
|
JetbrainsPhpstorm => runner.execute(*self, "JetBrains PhpStorm Plugins", || {
|
||||||
|
generic::run_jetbrains_phpstorm(ctx)
|
||||||
|
})?,
|
||||||
|
JetbrainsPycharm => runner.execute(*self, "JetBrains PyCharm Plugins", || {
|
||||||
|
generic::run_jetbrains_pycharm(ctx)
|
||||||
|
})?,
|
||||||
|
JetbrainsRider => runner.execute(*self, "JetBrains Rider Plugins", || generic::run_jetbrains_rider(ctx))?,
|
||||||
|
JetbrainsRubymine => runner.execute(*self, "JetBrains RubyMine Plugins", || {
|
||||||
|
generic::run_jetbrains_rubymine(ctx)
|
||||||
|
})?,
|
||||||
|
JetbrainsRustrover => runner.execute(*self, "JetBrains RustRover Plugins", || {
|
||||||
|
generic::run_jetbrains_rustrover(ctx)
|
||||||
|
})?,
|
||||||
|
JetbrainsToolbox => runner.execute(*self, "JetBrains Toolbox", || generic::run_jetbrains_toolbox(ctx))?,
|
||||||
|
JetbrainsWebstorm => runner.execute(*self, "JetBrains WebStorm Plugins", || {
|
||||||
|
generic::run_jetbrains_webstorm(ctx)
|
||||||
|
})?,
|
||||||
|
Jetpack => runner.execute(*self, "jetpack", || generic::run_jetpack(ctx))?,
|
||||||
|
Julia => runner.execute(*self, "julia", || generic::update_julia_packages(ctx))?,
|
||||||
|
Juliaup => runner.execute(*self, "juliaup", || generic::run_juliaup(ctx))?,
|
||||||
|
Kakoune => runner.execute(*self, "Kakoune", || kakoune::upgrade_kak_plug(ctx))?,
|
||||||
|
Krew => runner.execute(*self, "krew", || generic::run_krew_upgrade(ctx))?,
|
||||||
|
Lensfun => runner.execute(*self, "Lensfun's database update", || {
|
||||||
|
generic::run_lensfun_update_data(ctx)
|
||||||
|
})?,
|
||||||
|
Lure =>
|
||||||
|
{
|
||||||
|
#[cfg(target_os = "linux")]
|
||||||
|
runner.execute(*self, "LURE", || linux::run_lure_update(ctx))?
|
||||||
|
}
|
||||||
|
Macports =>
|
||||||
|
{
|
||||||
|
#[cfg(target_os = "macos")]
|
||||||
|
runner.execute(*self, "MacPorts", || macos::run_macports(ctx))?
|
||||||
|
}
|
||||||
|
Mamba => runner.execute(*self, "mamba", || generic::run_mamba_update(ctx))?,
|
||||||
|
Mandb =>
|
||||||
|
{
|
||||||
|
#[cfg(target_os = "linux")]
|
||||||
|
runner.execute(*self, "Manual Entries", || linux::run_mandb(ctx))?
|
||||||
|
}
|
||||||
|
Mas =>
|
||||||
|
{
|
||||||
|
#[cfg(target_os = "macos")]
|
||||||
|
runner.execute(*self, "App Store", || macos::run_mas(ctx))?
|
||||||
|
}
|
||||||
|
Maza =>
|
||||||
|
{
|
||||||
|
#[cfg(unix)]
|
||||||
|
runner.execute(*self, "maza", || unix::run_maza(ctx))?
|
||||||
|
}
|
||||||
|
Micro => runner.execute(*self, "micro", || generic::run_micro(ctx))?,
|
||||||
|
MicrosoftStore =>
|
||||||
|
{
|
||||||
|
#[cfg(windows)]
|
||||||
|
runner.execute(*self, "Microsoft Store", || windows::microsoft_store(ctx))?
|
||||||
|
}
|
||||||
|
Miktex => runner.execute(*self, "miktex", || generic::run_miktex_packages_update(ctx))?,
|
||||||
|
Mise =>
|
||||||
|
{
|
||||||
|
#[cfg(unix)]
|
||||||
|
runner.execute(*self, "mise", || unix::run_mise(ctx))?
|
||||||
|
}
|
||||||
|
Myrepos => runner.execute(*self, "myrepos", || generic::run_myrepos_update(ctx))?,
|
||||||
|
Nix => {
|
||||||
|
#[cfg(unix)]
|
||||||
|
runner.execute(*self, "nix", || unix::run_nix(ctx))?;
|
||||||
|
#[cfg(unix)]
|
||||||
|
runner.execute(*self, "nix upgrade-nix", || unix::run_nix_self_upgrade(ctx))?
|
||||||
|
}
|
||||||
|
NixHelper =>
|
||||||
|
{
|
||||||
|
#[cfg(unix)]
|
||||||
|
runner.execute(*self, "nh", || unix::run_nix_helper(ctx))?
|
||||||
|
}
|
||||||
|
Node => runner.execute(*self, "npm", || node::run_npm_upgrade(ctx))?,
|
||||||
|
Opam => runner.execute(*self, "opam", || generic::run_opam_update(ctx))?,
|
||||||
|
Pacdef =>
|
||||||
|
{
|
||||||
|
#[cfg(target_os = "linux")]
|
||||||
|
runner.execute(*self, "pacdef", || linux::run_pacdef(ctx))?
|
||||||
|
}
|
||||||
|
Pacstall =>
|
||||||
|
{
|
||||||
|
#[cfg(target_os = "linux")]
|
||||||
|
runner.execute(*self, "pacstall", || linux::run_pacstall(ctx))?
|
||||||
|
}
|
||||||
|
Pearl =>
|
||||||
|
{
|
||||||
|
#[cfg(unix)]
|
||||||
|
runner.execute(*self, "pearl", || unix::run_pearl(ctx))?
|
||||||
|
}
|
||||||
|
Pip3 => runner.execute(*self, "pip3", || generic::run_pip3_update(ctx))?,
|
||||||
|
PipReview => runner.execute(*self, "pip-review", || generic::run_pip_review_update(ctx))?,
|
||||||
|
PipReviewLocal => runner.execute(*self, "pip-review (local)", || {
|
||||||
|
generic::run_pip_review_local_update(ctx)
|
||||||
|
})?,
|
||||||
|
Pipupgrade => runner.execute(*self, "pipupgrade", || generic::run_pipupgrade_update(ctx))?,
|
||||||
|
Pipx => runner.execute(*self, "pipx", || generic::run_pipx_update(ctx))?,
|
||||||
|
Pipxu => runner.execute(*self, "pipxu", || generic::run_pipxu_update(ctx))?,
|
||||||
|
Pixi => runner.execute(*self, "pixi", || generic::run_pixi_update(ctx))?,
|
||||||
|
Pkg => {
|
||||||
|
#[cfg(target_os = "dragonfly")]
|
||||||
|
runner.execute(*self, "Dragonfly BSD Packages", || dragonfly::upgrade_packages(ctx))?;
|
||||||
|
#[cfg(target_os = "freebsd")]
|
||||||
|
runner.execute(*self, "FreeBSD Packages", || freebsd::upgrade_packages(ctx))?;
|
||||||
|
#[cfg(target_os = "openbsd")]
|
||||||
|
runner.execute(*self, "OpenBSD Packages", || openbsd::upgrade_packages(ctx))?;
|
||||||
|
#[cfg(target_os = "android")]
|
||||||
|
runner.execute(*self, "Termux Packages", || android::upgrade_packages(ctx))?
|
||||||
|
}
|
||||||
|
Pkgfile =>
|
||||||
|
{
|
||||||
|
#[cfg(target_os = "linux")]
|
||||||
|
runner.execute(*self, "pkgfile", || linux::run_pkgfile(ctx))?
|
||||||
|
}
|
||||||
|
Pkgin =>
|
||||||
|
{
|
||||||
|
#[cfg(unix)]
|
||||||
|
runner.execute(*self, "pkgin", || unix::run_pkgin(ctx))?
|
||||||
|
}
|
||||||
|
PlatformioCore => runner.execute(*self, "PlatformIO Core", || generic::run_platform_io(ctx))?,
|
||||||
|
Pnpm => runner.execute(*self, "pnpm", || node::run_pnpm_upgrade(ctx))?,
|
||||||
|
Poetry => runner.execute(*self, "Poetry", || generic::run_poetry(ctx))?,
|
||||||
|
Powershell => runner.execute(*self, "Powershell Modules Update", || generic::run_powershell(ctx))?,
|
||||||
|
Protonup =>
|
||||||
|
{
|
||||||
|
#[cfg(target_os = "linux")]
|
||||||
|
runner.execute(*self, "protonup", || linux::run_protonup_update(ctx))?
|
||||||
|
}
|
||||||
|
Pyenv =>
|
||||||
|
{
|
||||||
|
#[cfg(unix)]
|
||||||
|
runner.execute(*self, "pyenv", || unix::run_pyenv(ctx))?
|
||||||
|
}
|
||||||
|
Raco => runner.execute(*self, "raco", || generic::run_raco_update(ctx))?,
|
||||||
|
Rcm =>
|
||||||
|
{
|
||||||
|
#[cfg(unix)]
|
||||||
|
runner.execute(*self, "rcm", || unix::run_rcm(ctx))?
|
||||||
|
}
|
||||||
|
Remotes => {
|
||||||
|
if let Some(topgrades) = ctx.config().remote_topgrades() {
|
||||||
|
for remote_topgrade in topgrades
|
||||||
|
.iter()
|
||||||
|
.filter(|t| ctx.config().should_execute_remote(hostname(), t))
|
||||||
|
{
|
||||||
|
runner.execute(*self, format!("Remote ({remote_topgrade})"), || {
|
||||||
|
crate::ssh::ssh_step(ctx, remote_topgrade)
|
||||||
|
})?;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Restarts =>
|
||||||
|
{
|
||||||
|
#[cfg(target_os = "linux")]
|
||||||
|
runner.execute(*self, "Restarts", || linux::run_needrestart(ctx))?
|
||||||
|
}
|
||||||
|
Rtcl => runner.execute(*self, "rtcl", || generic::run_rtcl(ctx))?,
|
||||||
|
RubyGems => runner.execute(*self, "rubygems", || generic::run_rubygems(ctx))?,
|
||||||
|
Rustup => runner.execute(*self, "rustup", || generic::run_rustup(ctx))?,
|
||||||
|
Rye => runner.execute(*self, "rye", || generic::run_rye(ctx))?,
|
||||||
|
Scoop =>
|
||||||
|
{
|
||||||
|
#[cfg(windows)]
|
||||||
|
runner.execute(*self, "Scoop", || windows::run_scoop(ctx))?
|
||||||
|
}
|
||||||
|
Sdkman =>
|
||||||
|
{
|
||||||
|
#[cfg(unix)]
|
||||||
|
runner.execute(*self, "SDKMAN!", || unix::run_sdkman(ctx))?
|
||||||
|
}
|
||||||
|
SelfUpdate => {
|
||||||
|
#[cfg(feature = "self-update")]
|
||||||
|
{
|
||||||
|
if std::env::var("TOPGRADE_NO_SELF_UPGRADE").is_err() && !ctx.config().no_self_update() {
|
||||||
|
runner.execute(*self, "Self Update", || self_update::self_update(ctx))?;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Sheldon => runner.execute(*self, "sheldon", || generic::run_sheldon(ctx))?,
|
||||||
|
Shell => {
|
||||||
|
#[cfg(unix)]
|
||||||
|
{
|
||||||
|
runner.execute(*self, "zr", || zsh::run_zr(ctx))?;
|
||||||
|
runner.execute(*self, "antibody", || zsh::run_antibody(ctx))?;
|
||||||
|
runner.execute(*self, "antidote", || zsh::run_antidote(ctx))?;
|
||||||
|
runner.execute(*self, "antigen", || zsh::run_antigen(ctx))?;
|
||||||
|
runner.execute(*self, "zgenom", || zsh::run_zgenom(ctx))?;
|
||||||
|
runner.execute(*self, "zplug", || zsh::run_zplug(ctx))?;
|
||||||
|
runner.execute(*self, "zinit", || zsh::run_zinit(ctx))?;
|
||||||
|
runner.execute(*self, "zi", || zsh::run_zi(ctx))?;
|
||||||
|
runner.execute(*self, "zim", || zsh::run_zim(ctx))?;
|
||||||
|
runner.execute(*self, "oh-my-zsh", || zsh::run_oh_my_zsh(ctx))?;
|
||||||
|
runner.execute(*self, "oh-my-bash", || unix::run_oh_my_bash(ctx))?;
|
||||||
|
runner.execute(*self, "fisher", || unix::run_fisher(ctx))?;
|
||||||
|
runner.execute(*self, "bash-it", || unix::run_bashit(ctx))?;
|
||||||
|
runner.execute(*self, "oh-my-fish", || unix::run_oh_my_fish(ctx))?;
|
||||||
|
runner.execute(*self, "fish-plug", || unix::run_fish_plug(ctx))?;
|
||||||
|
runner.execute(*self, "fundle", || unix::run_fundle(ctx))?
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Snap =>
|
||||||
|
{
|
||||||
|
#[cfg(target_os = "linux")]
|
||||||
|
runner.execute(*self, "snap", || linux::run_snap(ctx))?
|
||||||
|
}
|
||||||
|
Sparkle =>
|
||||||
|
{
|
||||||
|
#[cfg(target_os = "macos")]
|
||||||
|
runner.execute(*self, "Sparkle", || macos::run_sparkle(ctx))?
|
||||||
|
}
|
||||||
|
Spicetify => runner.execute(*self, "spicetify", || generic::spicetify_upgrade(ctx))?,
|
||||||
|
Stack => runner.execute(*self, "stack", || generic::run_stack_update(ctx))?,
|
||||||
|
Stew => runner.execute(*self, "stew", || generic::run_stew(ctx))?,
|
||||||
|
System => {
|
||||||
|
#[cfg(target_os = "linux")]
|
||||||
|
{
|
||||||
|
// NOTE: Due to breaking `nu` updates, `packer.nu` needs to be updated before `nu` get updated
|
||||||
|
// by other package managers.
|
||||||
|
runner.execute(Shell, "packer.nu", || linux::run_packer_nu(ctx))?;
|
||||||
|
|
||||||
|
match ctx.distribution() {
|
||||||
|
Ok(distribution) => {
|
||||||
|
runner.execute(*self, "System update", || distribution.upgrade(ctx))?;
|
||||||
|
}
|
||||||
|
Err(e) => {
|
||||||
|
println!("{}", t!("Error detecting current distribution: {error}", error = e));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
runner.execute(*self, "pihole", || linux::run_pihole_update(ctx))?;
|
||||||
|
}
|
||||||
|
#[cfg(windows)]
|
||||||
|
runner.execute(*self, "Windows update", || windows::windows_update(ctx))?;
|
||||||
|
#[cfg(target_os = "macos")]
|
||||||
|
runner.execute(*self, "System update", || macos::upgrade_macos(ctx))?;
|
||||||
|
#[cfg(target_os = "freebsd")]
|
||||||
|
runner.execute(*self, "FreeBSD Upgrade", || freebsd::upgrade_freebsd(ctx))?;
|
||||||
|
#[cfg(target_os = "openbsd")]
|
||||||
|
runner.execute(*self, "OpenBSD Upgrade", || openbsd::upgrade_openbsd(ctx))?
|
||||||
|
}
|
||||||
|
Tldr => runner.execute(*self, "TLDR", || generic::run_tldr(ctx))?,
|
||||||
|
Tlmgr => runner.execute(*self, "tlmgr", || generic::run_tlmgr_update(ctx))?,
|
||||||
|
Tmux =>
|
||||||
|
{
|
||||||
|
#[cfg(unix)]
|
||||||
|
runner.execute(*self, "tmux", || tmux::run_tpm(ctx))?
|
||||||
|
}
|
||||||
|
Toolbx =>
|
||||||
|
{
|
||||||
|
#[cfg(target_os = "linux")]
|
||||||
|
runner.execute(*self, "toolbx", || toolbx::run_toolbx(ctx))?
|
||||||
|
}
|
||||||
|
Typst => runner.execute(*self, "Typst", || generic::run_typst(ctx))?,
|
||||||
|
Uv => runner.execute(*self, "uv", || generic::run_uv(ctx))?,
|
||||||
|
Vagrant => {
|
||||||
|
if ctx.config().should_run(Vagrant) {
|
||||||
|
if let Ok(boxes) = vagrant::collect_boxes(ctx) {
|
||||||
|
for vagrant_box in boxes {
|
||||||
|
runner.execute(*self, format!("Vagrant ({})", vagrant_box.smart_name()), || {
|
||||||
|
vagrant::topgrade_vagrant_box(ctx, &vagrant_box)
|
||||||
|
})?;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
runner.execute(*self, "Vagrant boxes", || vagrant::upgrade_vagrant_boxes(ctx))?;
|
||||||
|
}
|
||||||
|
Vcpkg => runner.execute(*self, "vcpkg", || generic::run_vcpkg_update(ctx))?,
|
||||||
|
Vim => {
|
||||||
|
runner.execute(*self, "vim", || vim::upgrade_vim(ctx))?;
|
||||||
|
runner.execute(*self, "Neovim", || vim::upgrade_neovim(ctx))?;
|
||||||
|
runner.execute(*self, "The Ultimate vimrc", || vim::upgrade_ultimate_vimrc(ctx))?;
|
||||||
|
runner.execute(*self, "voom", || vim::run_voom(ctx))?
|
||||||
|
}
|
||||||
|
VoltaPackages => runner.execute(*self, "volta packages", || node::run_volta_packages_upgrade(ctx))?,
|
||||||
|
Vscode => runner.execute(*self, "Visual Studio Code extensions", || {
|
||||||
|
generic::run_vscode_extensions_update(ctx)
|
||||||
|
})?,
|
||||||
|
VscodeInsiders => runner.execute(*self, "Visual Studio Code Insiders extensions", || {
|
||||||
|
generic::run_vscode_insiders_extensions_update(ctx)
|
||||||
|
})?,
|
||||||
|
Vscodium => runner.execute(*self, "VSCodium extensions", || {
|
||||||
|
generic::run_vscodium_extensions_update(ctx)
|
||||||
|
})?,
|
||||||
|
VscodiumInsiders => runner.execute(*self, "VSCodium Insiders extensions", || {
|
||||||
|
generic::run_vscodium_insiders_extensions_update(ctx)
|
||||||
|
})?,
|
||||||
|
Waydroid =>
|
||||||
|
{
|
||||||
|
#[cfg(target_os = "linux")]
|
||||||
|
runner.execute(*self, "Waydroid", || linux::run_waydroid(ctx))?
|
||||||
|
}
|
||||||
|
Winget =>
|
||||||
|
{
|
||||||
|
#[cfg(windows)]
|
||||||
|
runner.execute(*self, "Winget", || windows::run_winget(ctx))?
|
||||||
|
}
|
||||||
|
Wsl =>
|
||||||
|
{
|
||||||
|
#[cfg(windows)]
|
||||||
|
runner.execute(*self, "WSL", || windows::run_wsl_topgrade(ctx))?
|
||||||
|
}
|
||||||
|
WslUpdate =>
|
||||||
|
{
|
||||||
|
#[cfg(windows)]
|
||||||
|
runner.execute(*self, "Update WSL", || windows::update_wsl(ctx))?
|
||||||
|
}
|
||||||
|
Xcodes =>
|
||||||
|
{
|
||||||
|
#[cfg(target_os = "macos")]
|
||||||
|
runner.execute(*self, "Xcodes", || macos::update_xcodes(ctx))?
|
||||||
|
}
|
||||||
|
Yadm =>
|
||||||
|
{
|
||||||
|
#[cfg(unix)]
|
||||||
|
runner.execute(*self, "yadm", || unix::run_yadm(ctx))?
|
||||||
|
}
|
||||||
|
Yarn => runner.execute(*self, "yarn", || node::run_yarn_upgrade(ctx))?,
|
||||||
|
Yazi => runner.execute(*self, "Yazi packages", || generic::run_yazi(ctx))?,
|
||||||
|
Zigup => runner.execute(*self, "zigup", || generic::run_zigup(ctx))?,
|
||||||
|
Zvm => runner.execute(*self, "ZVM", || generic::run_zvm(ctx))?,
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[allow(clippy::too_many_lines)]
|
||||||
|
pub(crate) fn default_steps() -> Vec<Step> {
|
||||||
|
// For now, SelfRenamer and SelfUpdate isn't included as they're ran before the other non-steps (pre-commands, sudo, etc)
|
||||||
|
|
||||||
|
use Step::*;
|
||||||
|
// Could probably have a smaller starting capacity, but this at least ensures only 2 allocations:
|
||||||
|
// initial and shrink
|
||||||
|
let mut steps = Vec::with_capacity(Step::COUNT);
|
||||||
|
|
||||||
|
// Not combined with other generic steps to preserve the order as it was in main.rs originally,
|
||||||
|
// but this can be changed in the future.
|
||||||
|
steps.push(Remotes);
|
||||||
|
|
||||||
|
#[cfg(windows)]
|
||||||
|
steps.extend_from_slice(&[Wsl, WslUpdate, Chocolatey, Scoop, Winget, System, MicrosoftStore]);
|
||||||
|
|
||||||
|
#[cfg(target_os = "macos")]
|
||||||
|
steps.extend_from_slice(&[BrewFormula, BrewCask, Macports, Xcodes, Sparkle, Mas, System]);
|
||||||
|
|
||||||
|
#[cfg(target_os = "dragonfly")]
|
||||||
|
steps.extend_from_slice(&[Pkg, Audit]);
|
||||||
|
|
||||||
|
#[cfg(target_os = "freebsd")]
|
||||||
|
steps.extend_from_slice(&[Pkg, System, Audit]);
|
||||||
|
|
||||||
|
#[cfg(target_os = "openbsd")]
|
||||||
|
steps.extend_from_slice(&[Pkg, System]);
|
||||||
|
|
||||||
|
#[cfg(target_os = "android")]
|
||||||
|
steps.push(Pkg);
|
||||||
|
|
||||||
|
#[cfg(target_os = "linux")]
|
||||||
|
steps.extend_from_slice(&[
|
||||||
|
System,
|
||||||
|
ConfigUpdate,
|
||||||
|
AM,
|
||||||
|
AppMan,
|
||||||
|
DebGet,
|
||||||
|
Toolbx,
|
||||||
|
Snap,
|
||||||
|
Pacstall,
|
||||||
|
Pacdef,
|
||||||
|
Protonup,
|
||||||
|
Distrobox,
|
||||||
|
DkpPacman,
|
||||||
|
Firmware,
|
||||||
|
Restarts,
|
||||||
|
Flatpak,
|
||||||
|
BrewFormula,
|
||||||
|
Lure,
|
||||||
|
Waydroid,
|
||||||
|
AutoCpufreq,
|
||||||
|
CinnamonSpices,
|
||||||
|
Mandb,
|
||||||
|
Pkgfile,
|
||||||
|
]);
|
||||||
|
|
||||||
|
#[cfg(unix)]
|
||||||
|
steps.extend_from_slice(&[
|
||||||
|
Yadm,
|
||||||
|
Nix,
|
||||||
|
NixHelper,
|
||||||
|
Guix,
|
||||||
|
HomeManager,
|
||||||
|
Asdf,
|
||||||
|
Mise,
|
||||||
|
Pkgin,
|
||||||
|
BunPackages,
|
||||||
|
Shell,
|
||||||
|
Tmux,
|
||||||
|
Pearl,
|
||||||
|
#[cfg(not(any(target_os = "macos", target_os = "android")))]
|
||||||
|
GnomeShellExtensions,
|
||||||
|
Pyenv,
|
||||||
|
Sdkman,
|
||||||
|
Rcm,
|
||||||
|
Maza,
|
||||||
|
Atuin,
|
||||||
|
]);
|
||||||
|
|
||||||
|
#[cfg(not(any(
|
||||||
|
target_os = "freebsd",
|
||||||
|
target_os = "openbsd",
|
||||||
|
target_os = "netbsd",
|
||||||
|
target_os = "dragonfly"
|
||||||
|
)))]
|
||||||
|
steps.push(Atom);
|
||||||
|
|
||||||
|
// The following update function should be executed on all OSes.
|
||||||
|
steps.extend_from_slice(&[
|
||||||
|
Fossil,
|
||||||
|
Elan,
|
||||||
|
Rye,
|
||||||
|
Rustup,
|
||||||
|
Juliaup,
|
||||||
|
Dotnet,
|
||||||
|
Choosenim,
|
||||||
|
Cargo,
|
||||||
|
Flutter,
|
||||||
|
Go,
|
||||||
|
Emacs,
|
||||||
|
Opam,
|
||||||
|
Vcpkg,
|
||||||
|
Pipx,
|
||||||
|
Pipxu,
|
||||||
|
Vscode,
|
||||||
|
VscodeInsiders,
|
||||||
|
Vscodium,
|
||||||
|
VscodiumInsiders,
|
||||||
|
Conda,
|
||||||
|
Mamba,
|
||||||
|
Pixi,
|
||||||
|
Miktex,
|
||||||
|
Pip3,
|
||||||
|
PipReview,
|
||||||
|
PipReviewLocal,
|
||||||
|
Pipupgrade,
|
||||||
|
Ghcup,
|
||||||
|
Stack,
|
||||||
|
Tldr,
|
||||||
|
Tlmgr,
|
||||||
|
Myrepos,
|
||||||
|
Chezmoi,
|
||||||
|
Jetpack,
|
||||||
|
Vim,
|
||||||
|
Kakoune,
|
||||||
|
Helix,
|
||||||
|
Node,
|
||||||
|
Yarn,
|
||||||
|
Pnpm,
|
||||||
|
VoltaPackages,
|
||||||
|
Containers,
|
||||||
|
Deno,
|
||||||
|
Composer,
|
||||||
|
Krew,
|
||||||
|
Helm,
|
||||||
|
Gem,
|
||||||
|
RubyGems,
|
||||||
|
Julia,
|
||||||
|
Haxelib,
|
||||||
|
Sheldon,
|
||||||
|
Stew,
|
||||||
|
Rtcl,
|
||||||
|
Bin,
|
||||||
|
Gcloud,
|
||||||
|
Micro,
|
||||||
|
Raco,
|
||||||
|
Spicetify,
|
||||||
|
GithubCliExtensions,
|
||||||
|
Bob,
|
||||||
|
Certbot,
|
||||||
|
GitRepos,
|
||||||
|
ClamAvDb,
|
||||||
|
PlatformioCore,
|
||||||
|
Lensfun,
|
||||||
|
Poetry,
|
||||||
|
Uv,
|
||||||
|
Zvm,
|
||||||
|
Aqua,
|
||||||
|
Bun,
|
||||||
|
Zigup,
|
||||||
|
JetbrainsToolbox,
|
||||||
|
AndroidStudio,
|
||||||
|
JetbrainsAqua,
|
||||||
|
JetbrainsClion,
|
||||||
|
JetbrainsDatagrip,
|
||||||
|
JetbrainsDataspell,
|
||||||
|
// JetBrains dotCover has no CLI
|
||||||
|
// JetBrains dotMemory has no CLI
|
||||||
|
// JetBrains dotPeek has no CLI
|
||||||
|
// JetBrains dotTrace has no CLI
|
||||||
|
// JetBrains Fleet has a different CLI without a `fleet update` command.
|
||||||
|
JetbrainsGateway,
|
||||||
|
JetbrainsGoland,
|
||||||
|
JetbrainsIdea,
|
||||||
|
JetbrainsMps,
|
||||||
|
JetbrainsPhpstorm,
|
||||||
|
JetbrainsPycharm,
|
||||||
|
// JetBrains ReSharper has no CLI (it's a VSCode extension)
|
||||||
|
// JetBrains ReSharper C++ has no CLI (it's a VSCode extension)
|
||||||
|
JetbrainsRider,
|
||||||
|
JetbrainsRubymine,
|
||||||
|
JetbrainsRustrover,
|
||||||
|
// JetBrains Space Desktop does not have a CLI
|
||||||
|
JetbrainsWebstorm,
|
||||||
|
Yazi,
|
||||||
|
Powershell,
|
||||||
|
CustomCommands,
|
||||||
|
Vagrant,
|
||||||
|
Typst,
|
||||||
|
]);
|
||||||
|
|
||||||
|
steps.shrink_to_fit();
|
||||||
|
|
||||||
|
steps
|
||||||
|
}
|
||||||
@@ -142,13 +142,13 @@ pub fn run_containers(ctx: &ExecutionContext) -> Result<()> {
|
|||||||
|
|
||||||
for container in &containers {
|
for container in &containers {
|
||||||
debug!("Pulling container '{}'", container);
|
debug!("Pulling container '{}'", container);
|
||||||
let args = vec![
|
let mut args = vec!["pull", container.repo_tag.as_str()];
|
||||||
"pull",
|
if container.platform.as_str() != "/" {
|
||||||
container.repo_tag.as_str(),
|
args.push("--platform");
|
||||||
"--platform",
|
args.push(container.platform.as_str());
|
||||||
container.platform.as_str(),
|
}
|
||||||
];
|
|
||||||
let mut exec = ctx.run_type().execute(&crt);
|
let mut exec = ctx.execute(&crt);
|
||||||
|
|
||||||
if let Err(e) = exec.args(&args).status_checked() {
|
if let Err(e) = exec.args(&args).status_checked() {
|
||||||
error!("Pulling container '{}' failed: {}", container, e);
|
error!("Pulling container '{}' failed: {}", container, e);
|
||||||
@@ -177,12 +177,7 @@ pub fn run_containers(ctx: &ExecutionContext) -> Result<()> {
|
|||||||
if ctx.config().cleanup() {
|
if ctx.config().cleanup() {
|
||||||
// Remove dangling images
|
// Remove dangling images
|
||||||
debug!("Removing dangling images");
|
debug!("Removing dangling images");
|
||||||
if let Err(e) = ctx
|
if let Err(e) = ctx.execute(&crt).args(["image", "prune", "-f"]).status_checked() {
|
||||||
.run_type()
|
|
||||||
.execute(&crt)
|
|
||||||
.args(["image", "prune", "-f"])
|
|
||||||
.status_checked()
|
|
||||||
{
|
|
||||||
error!("Removing dangling images failed: {}", e);
|
error!("Removing dangling images failed: {}", e);
|
||||||
success = false;
|
success = false;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,9 +8,9 @@ use rust_i18n::t;
|
|||||||
|
|
||||||
use crate::command::CommandExt;
|
use crate::command::CommandExt;
|
||||||
use crate::execution_context::ExecutionContext;
|
use crate::execution_context::ExecutionContext;
|
||||||
|
use crate::step::Step;
|
||||||
use crate::terminal::print_separator;
|
use crate::terminal::print_separator;
|
||||||
use crate::utils::{require, require_option, PathExt};
|
use crate::utils::{require, require_option, PathExt};
|
||||||
use crate::Step;
|
|
||||||
|
|
||||||
const EMACS_UPGRADE: &str = include_str!("emacs.el");
|
const EMACS_UPGRADE: &str = include_str!("emacs.el");
|
||||||
#[cfg(windows)]
|
#[cfg(windows)]
|
||||||
@@ -60,7 +60,7 @@ impl Emacs {
|
|||||||
fn update_doom(doom: &Path, ctx: &ExecutionContext) -> Result<()> {
|
fn update_doom(doom: &Path, ctx: &ExecutionContext) -> Result<()> {
|
||||||
print_separator("Doom Emacs");
|
print_separator("Doom Emacs");
|
||||||
|
|
||||||
let mut command = ctx.run_type().execute(doom);
|
let mut command = ctx.execute(doom);
|
||||||
if ctx.config().yes(Step::Emacs) {
|
if ctx.config().yes(Step::Emacs) {
|
||||||
command.arg("--force");
|
command.arg("--force");
|
||||||
}
|
}
|
||||||
@@ -84,7 +84,7 @@ impl Emacs {
|
|||||||
|
|
||||||
print_separator("Emacs");
|
print_separator("Emacs");
|
||||||
|
|
||||||
let mut command = ctx.run_type().execute(emacs);
|
let mut command = ctx.execute(emacs);
|
||||||
|
|
||||||
command
|
command
|
||||||
.args(["--batch", "--debug-init", "-l"])
|
.args(["--batch", "--debug-init", "-l"])
|
||||||
|
|||||||
1025
src/steps/generic.rs
1025
src/steps/generic.rs
File diff suppressed because it is too large
Load Diff
@@ -13,8 +13,8 @@ use tokio::runtime;
|
|||||||
use tracing::{debug, error};
|
use tracing::{debug, error};
|
||||||
|
|
||||||
use crate::command::CommandExt;
|
use crate::command::CommandExt;
|
||||||
use crate::config::Step;
|
|
||||||
use crate::execution_context::ExecutionContext;
|
use crate::execution_context::ExecutionContext;
|
||||||
|
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::{require, PathExt};
|
||||||
@@ -58,9 +58,10 @@ pub fn run_git_pull(ctx: &ExecutionContext) -> Result<()> {
|
|||||||
repos.insert_if_repo(HOME_DIR.join(".dotfiles"));
|
repos.insert_if_repo(HOME_DIR.join(".dotfiles"));
|
||||||
}
|
}
|
||||||
|
|
||||||
let powershell = crate::steps::powershell::Powershell::new();
|
if let Some(powershell) = ctx.powershell() {
|
||||||
if let Some(profile) = powershell.profile() {
|
if let Some(profile) = powershell.profile() {
|
||||||
repos.insert_if_repo(profile);
|
repos.insert_if_repo(profile);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -15,7 +15,7 @@ pub fn run_go_global_update(ctx: &ExecutionContext) -> Result<()> {
|
|||||||
|
|
||||||
print_separator("go-global-update");
|
print_separator("go-global-update");
|
||||||
|
|
||||||
ctx.run_type().execute(go_global_update).status_checked()
|
ctx.execute(go_global_update).status_checked()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <https://github.com/nao1215/gup>
|
/// <https://github.com/nao1215/gup>
|
||||||
@@ -24,7 +24,7 @@ pub fn run_go_gup(ctx: &ExecutionContext) -> Result<()> {
|
|||||||
|
|
||||||
print_separator("gup");
|
print_separator("gup");
|
||||||
|
|
||||||
ctx.run_type().execute(gup).arg("update").status_checked()
|
ctx.execute(gup).arg("update").status_checked()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get the path of a Go binary.
|
/// Get the path of a Go binary.
|
||||||
|
|||||||
@@ -12,11 +12,8 @@ pub fn upgrade_kak_plug(ctx: &ExecutionContext) -> Result<()> {
|
|||||||
|
|
||||||
print_separator("Kakoune");
|
print_separator("Kakoune");
|
||||||
|
|
||||||
// TODO: Why supress output for this command?
|
// TODO: Why suppress output for this command?
|
||||||
ctx.run_type()
|
ctx.execute(kak).args(["-ui", "dummy", "-e", UPGRADE_KAK]).output()?;
|
||||||
.execute(kak)
|
|
||||||
.args(["-ui", "dummy", "-e", UPGRADE_KAK])
|
|
||||||
.output()?;
|
|
||||||
|
|
||||||
println!("{}", t!("Plugins upgraded"));
|
println!("{}", t!("Plugins upgraded"));
|
||||||
|
|
||||||
|
|||||||
@@ -4,7 +4,6 @@ use std::os::unix::fs::MetadataExt;
|
|||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
use std::process::Command;
|
use std::process::Command;
|
||||||
|
|
||||||
use crate::utils::{get_require_sudo_string, require_option};
|
|
||||||
use crate::HOME_DIR;
|
use crate::HOME_DIR;
|
||||||
use color_eyre::eyre::Result;
|
use color_eyre::eyre::Result;
|
||||||
#[cfg(target_os = "linux")]
|
#[cfg(target_os = "linux")]
|
||||||
@@ -93,14 +92,10 @@ impl NPM {
|
|||||||
fn upgrade(&self, ctx: &ExecutionContext, use_sudo: bool) -> Result<()> {
|
fn upgrade(&self, ctx: &ExecutionContext, use_sudo: bool) -> Result<()> {
|
||||||
let args = ["update", self.global_location_arg()];
|
let args = ["update", self.global_location_arg()];
|
||||||
if use_sudo {
|
if use_sudo {
|
||||||
let sudo = require_option(ctx.sudo().clone(), get_require_sudo_string())?;
|
let sudo = ctx.require_sudo()?;
|
||||||
ctx.run_type()
|
sudo.execute(ctx, &self.command)?.args(args).status_checked()?;
|
||||||
.execute(sudo)
|
|
||||||
.arg(&self.command)
|
|
||||||
.args(args)
|
|
||||||
.status_checked()?;
|
|
||||||
} else {
|
} else {
|
||||||
ctx.run_type().execute(&self.command).args(args).status_checked()?;
|
ctx.execute(&self.command).args(args).status_checked()?;
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
@@ -122,15 +117,11 @@ impl NPM {
|
|||||||
|
|
||||||
struct Yarn {
|
struct Yarn {
|
||||||
command: PathBuf,
|
command: PathBuf,
|
||||||
yarn: Option<PathBuf>,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Yarn {
|
impl Yarn {
|
||||||
fn new(command: PathBuf) -> Self {
|
fn new(command: PathBuf) -> Self {
|
||||||
Self {
|
Self { command }
|
||||||
command,
|
|
||||||
yarn: require("yarn").ok(),
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn has_global_subcmd(&self) -> bool {
|
fn has_global_subcmd(&self) -> bool {
|
||||||
@@ -157,14 +148,10 @@ impl Yarn {
|
|||||||
let args = ["global", "upgrade"];
|
let args = ["global", "upgrade"];
|
||||||
|
|
||||||
if use_sudo {
|
if use_sudo {
|
||||||
let sudo = require_option(ctx.sudo().clone(), get_require_sudo_string())?;
|
let sudo = ctx.require_sudo()?;
|
||||||
ctx.run_type()
|
sudo.execute(ctx, &self.command)?.args(args).status_checked()?;
|
||||||
.execute(sudo)
|
|
||||||
.arg(self.yarn.as_ref().unwrap_or(&self.command))
|
|
||||||
.args(args)
|
|
||||||
.status_checked()?;
|
|
||||||
} else {
|
} else {
|
||||||
ctx.run_type().execute(&self.command).args(args).status_checked()?;
|
ctx.execute(&self.command).args(args).status_checked()?;
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
@@ -245,11 +232,7 @@ impl Deno {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ctx.run_type()
|
ctx.execute(&self.command).arg("upgrade").args(args).status_checked()?;
|
||||||
.execute(&self.command)
|
|
||||||
.arg("upgrade")
|
|
||||||
.args(args)
|
|
||||||
.status_checked()?;
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -376,7 +359,6 @@ pub fn run_volta_packages_upgrade(ctx: &ExecutionContext) -> Result<()> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
let list_output = ctx
|
let list_output = ctx
|
||||||
.run_type()
|
|
||||||
.execute(&volta)
|
.execute(&volta)
|
||||||
.args(["list", "--format=plain"])
|
.args(["list", "--format=plain"])
|
||||||
.output_checked_utf8()?
|
.output_checked_utf8()?
|
||||||
@@ -400,10 +382,7 @@ pub fn run_volta_packages_upgrade(ctx: &ExecutionContext) -> Result<()> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
for package in &installed_packages {
|
for package in &installed_packages {
|
||||||
ctx.run_type()
|
ctx.execute(&volta).args(["install", package]).status_checked()?;
|
||||||
.execute(&volta)
|
|
||||||
.args(["install", package])
|
|
||||||
.status_checked()?;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
|
|||||||
@@ -1,10 +1,10 @@
|
|||||||
use crate::command::CommandExt;
|
use crate::command::CommandExt;
|
||||||
use crate::execution_context::ExecutionContext;
|
use crate::execution_context::ExecutionContext;
|
||||||
|
use crate::step::Step;
|
||||||
use crate::terminal::print_separator;
|
use crate::terminal::print_separator;
|
||||||
use crate::utils::require;
|
use crate::utils::require;
|
||||||
use crate::utils::which;
|
use crate::utils::which;
|
||||||
use crate::Step;
|
use color_eyre::Result;
|
||||||
use color_eyre::eyre::Result;
|
|
||||||
|
|
||||||
pub fn upgrade_packages(ctx: &ExecutionContext) -> Result<()> {
|
pub fn upgrade_packages(ctx: &ExecutionContext) -> Result<()> {
|
||||||
//let pkg = require("pkg")?;
|
//let pkg = require("pkg")?;
|
||||||
@@ -14,7 +14,7 @@ pub fn upgrade_packages(ctx: &ExecutionContext) -> Result<()> {
|
|||||||
|
|
||||||
let is_nala = pkg.ends_with("nala");
|
let is_nala = pkg.ends_with("nala");
|
||||||
|
|
||||||
let mut command = ctx.run_type().execute(&pkg);
|
let mut command = ctx.execute(&pkg);
|
||||||
command.arg("upgrade");
|
command.arg("upgrade");
|
||||||
|
|
||||||
if ctx.config().yes(Step::System) {
|
if ctx.config().yes(Step::System) {
|
||||||
@@ -23,10 +23,10 @@ pub fn upgrade_packages(ctx: &ExecutionContext) -> Result<()> {
|
|||||||
command.status_checked()?;
|
command.status_checked()?;
|
||||||
|
|
||||||
if !is_nala && ctx.config().cleanup() {
|
if !is_nala && ctx.config().cleanup() {
|
||||||
ctx.run_type().execute(&pkg).arg("clean").status_checked()?;
|
ctx.execute(&pkg).arg("clean").status_checked()?;
|
||||||
|
|
||||||
let apt = require("apt")?;
|
let apt = require("apt")?;
|
||||||
let mut command = ctx.run_type().execute(apt);
|
let mut command = ctx.execute(apt);
|
||||||
command.arg("autoremove");
|
command.arg("autoremove");
|
||||||
if ctx.config().yes(Step::System) {
|
if ctx.config().yes(Step::System) {
|
||||||
command.arg("-y");
|
command.arg("-y");
|
||||||
|
|||||||
@@ -3,16 +3,16 @@ use std::ffi::OsString;
|
|||||||
use std::path::{Path, PathBuf};
|
use std::path::{Path, PathBuf};
|
||||||
|
|
||||||
use color_eyre::eyre;
|
use color_eyre::eyre;
|
||||||
use color_eyre::eyre::Result;
|
use color_eyre::eyre::{Context, Result};
|
||||||
use rust_i18n::t;
|
use rust_i18n::t;
|
||||||
use walkdir::WalkDir;
|
use walkdir::WalkDir;
|
||||||
|
|
||||||
use crate::command::CommandExt;
|
use crate::command::CommandExt;
|
||||||
use crate::error::TopgradeError;
|
use crate::error::TopgradeError;
|
||||||
use crate::execution_context::ExecutionContext;
|
use crate::execution_context::ExecutionContext;
|
||||||
use crate::utils::require_option;
|
use crate::step::Step;
|
||||||
use crate::utils::which;
|
use crate::utils::which;
|
||||||
use crate::{config, Step};
|
use crate::{config, output_changed_message};
|
||||||
|
|
||||||
fn get_execution_path() -> OsString {
|
fn get_execution_path() -> OsString {
|
||||||
let mut path = OsString::from("/usr/bin:");
|
let mut path = OsString::from("/usr/bin:");
|
||||||
@@ -32,13 +32,12 @@ pub struct YayParu {
|
|||||||
impl ArchPackageManager for YayParu {
|
impl ArchPackageManager for YayParu {
|
||||||
fn upgrade(&self, ctx: &ExecutionContext) -> Result<()> {
|
fn upgrade(&self, ctx: &ExecutionContext) -> Result<()> {
|
||||||
if ctx.config().show_arch_news() {
|
if ctx.config().show_arch_news() {
|
||||||
ctx.run_type()
|
ctx.execute(&self.executable)
|
||||||
.execute(&self.executable)
|
|
||||||
.arg("-Pw")
|
.arg("-Pw")
|
||||||
.status_checked_with_codes(&[1, 0])?;
|
.status_checked_with_codes(&[1, 0])?;
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut command = ctx.run_type().execute(&self.executable);
|
let mut command = ctx.execute(&self.executable);
|
||||||
|
|
||||||
command
|
command
|
||||||
.arg("--pacman")
|
.arg("--pacman")
|
||||||
@@ -53,7 +52,7 @@ impl ArchPackageManager for YayParu {
|
|||||||
command.status_checked()?;
|
command.status_checked()?;
|
||||||
|
|
||||||
if ctx.config().cleanup() {
|
if ctx.config().cleanup() {
|
||||||
let mut command = ctx.run_type().execute(&self.executable);
|
let mut command = ctx.execute(&self.executable);
|
||||||
command.arg("--pacman").arg(&self.pacman).arg("-Scc");
|
command.arg("--pacman").arg(&self.pacman).arg("-Scc");
|
||||||
if ctx.config().yes(Step::System) {
|
if ctx.config().yes(Step::System) {
|
||||||
command.arg("--noconfirm");
|
command.arg("--noconfirm");
|
||||||
@@ -80,7 +79,7 @@ pub struct GarudaUpdate {
|
|||||||
|
|
||||||
impl ArchPackageManager for GarudaUpdate {
|
impl ArchPackageManager for GarudaUpdate {
|
||||||
fn upgrade(&self, ctx: &ExecutionContext) -> Result<()> {
|
fn upgrade(&self, ctx: &ExecutionContext) -> Result<()> {
|
||||||
let mut command = ctx.run_type().execute(&self.executable);
|
let mut command = ctx.execute(&self.executable);
|
||||||
|
|
||||||
command
|
command
|
||||||
.env("PATH", get_execution_path())
|
.env("PATH", get_execution_path())
|
||||||
@@ -111,7 +110,7 @@ pub struct Trizen {
|
|||||||
|
|
||||||
impl ArchPackageManager for Trizen {
|
impl ArchPackageManager for Trizen {
|
||||||
fn upgrade(&self, ctx: &ExecutionContext) -> Result<()> {
|
fn upgrade(&self, ctx: &ExecutionContext) -> Result<()> {
|
||||||
let mut command = ctx.run_type().execute(&self.executable);
|
let mut command = ctx.execute(&self.executable);
|
||||||
|
|
||||||
command
|
command
|
||||||
.arg("-Syu")
|
.arg("-Syu")
|
||||||
@@ -124,7 +123,7 @@ impl ArchPackageManager for Trizen {
|
|||||||
command.status_checked()?;
|
command.status_checked()?;
|
||||||
|
|
||||||
if ctx.config().cleanup() {
|
if ctx.config().cleanup() {
|
||||||
let mut command = ctx.run_type().execute(&self.executable);
|
let mut command = ctx.execute(&self.executable);
|
||||||
command.arg("-Sc");
|
command.arg("-Sc");
|
||||||
if ctx.config().yes(Step::System) {
|
if ctx.config().yes(Step::System) {
|
||||||
command.arg("--noconfirm");
|
command.arg("--noconfirm");
|
||||||
@@ -150,20 +149,17 @@ pub struct Pacman {
|
|||||||
|
|
||||||
impl ArchPackageManager for Pacman {
|
impl ArchPackageManager for Pacman {
|
||||||
fn upgrade(&self, ctx: &ExecutionContext) -> Result<()> {
|
fn upgrade(&self, ctx: &ExecutionContext) -> Result<()> {
|
||||||
let sudo = require_option(ctx.sudo().as_ref(), "sudo is required to run pacman".into())?;
|
let sudo = ctx.require_sudo()?;
|
||||||
let mut command = ctx.run_type().execute(sudo);
|
let mut command = sudo.execute(ctx, &self.executable)?;
|
||||||
command
|
command.arg("-Syu").env("PATH", get_execution_path());
|
||||||
.arg(&self.executable)
|
|
||||||
.arg("-Syu")
|
|
||||||
.env("PATH", get_execution_path());
|
|
||||||
if ctx.config().yes(Step::System) {
|
if ctx.config().yes(Step::System) {
|
||||||
command.arg("--noconfirm");
|
command.arg("--noconfirm");
|
||||||
}
|
}
|
||||||
command.status_checked()?;
|
command.status_checked()?;
|
||||||
|
|
||||||
if ctx.config().cleanup() {
|
if ctx.config().cleanup() {
|
||||||
let mut command = ctx.run_type().execute(sudo);
|
let mut command = sudo.execute(ctx, &self.executable)?;
|
||||||
command.arg(&self.executable).arg("-Scc");
|
command.arg("-Scc");
|
||||||
if ctx.config().yes(Step::System) {
|
if ctx.config().yes(Step::System) {
|
||||||
command.arg("--noconfirm");
|
command.arg("--noconfirm");
|
||||||
}
|
}
|
||||||
@@ -196,7 +192,7 @@ impl Pikaur {
|
|||||||
|
|
||||||
impl ArchPackageManager for Pikaur {
|
impl ArchPackageManager for Pikaur {
|
||||||
fn upgrade(&self, ctx: &ExecutionContext) -> Result<()> {
|
fn upgrade(&self, ctx: &ExecutionContext) -> Result<()> {
|
||||||
let mut command = ctx.run_type().execute(&self.executable);
|
let mut command = ctx.execute(&self.executable);
|
||||||
|
|
||||||
command
|
command
|
||||||
.arg("-Syu")
|
.arg("-Syu")
|
||||||
@@ -210,7 +206,7 @@ impl ArchPackageManager for Pikaur {
|
|||||||
command.status_checked()?;
|
command.status_checked()?;
|
||||||
|
|
||||||
if ctx.config().cleanup() {
|
if ctx.config().cleanup() {
|
||||||
let mut command = ctx.run_type().execute(&self.executable);
|
let mut command = ctx.execute(&self.executable);
|
||||||
command.arg("-Sc");
|
command.arg("-Sc");
|
||||||
if ctx.config().yes(Step::System) {
|
if ctx.config().yes(Step::System) {
|
||||||
command.arg("--noconfirm");
|
command.arg("--noconfirm");
|
||||||
@@ -235,7 +231,7 @@ impl Pamac {
|
|||||||
}
|
}
|
||||||
impl ArchPackageManager for Pamac {
|
impl ArchPackageManager for Pamac {
|
||||||
fn upgrade(&self, ctx: &ExecutionContext) -> Result<()> {
|
fn upgrade(&self, ctx: &ExecutionContext) -> Result<()> {
|
||||||
let mut command = ctx.run_type().execute(&self.executable);
|
let mut command = ctx.execute(&self.executable);
|
||||||
|
|
||||||
command
|
command
|
||||||
.arg("upgrade")
|
.arg("upgrade")
|
||||||
@@ -249,7 +245,7 @@ impl ArchPackageManager for Pamac {
|
|||||||
command.status_checked()?;
|
command.status_checked()?;
|
||||||
|
|
||||||
if ctx.config().cleanup() {
|
if ctx.config().cleanup() {
|
||||||
let mut command = ctx.run_type().execute(&self.executable);
|
let mut command = ctx.execute(&self.executable);
|
||||||
command.arg("clean");
|
command.arg("clean");
|
||||||
if ctx.config().yes(Step::System) {
|
if ctx.config().yes(Step::System) {
|
||||||
command.arg("--no-confirm");
|
command.arg("--no-confirm");
|
||||||
@@ -277,15 +273,12 @@ impl ArchPackageManager for Aura {
|
|||||||
fn upgrade(&self, ctx: &ExecutionContext) -> Result<()> {
|
fn upgrade(&self, ctx: &ExecutionContext) -> Result<()> {
|
||||||
use semver::Version;
|
use semver::Version;
|
||||||
|
|
||||||
let version_cmd_output = ctx
|
let version_cmd_output = ctx.execute(&self.executable).arg("--version").output_checked_utf8()?;
|
||||||
.run_type()
|
|
||||||
.execute(&self.executable)
|
|
||||||
.arg("--version")
|
|
||||||
.output_checked_utf8()?;
|
|
||||||
// Output will be something like: "aura x.x.x\n"
|
// Output will be something like: "aura x.x.x\n"
|
||||||
let version_cmd_stdout = version_cmd_output.stdout;
|
let version_cmd_stdout = version_cmd_output.stdout;
|
||||||
let version_str = version_cmd_stdout.trim_start_matches("aura ").trim_end();
|
let version_str = version_cmd_stdout.trim_start_matches("aura ").trim_end();
|
||||||
let version = Version::parse(version_str).expect("invalid version");
|
let version = Version::parse(version_str)
|
||||||
|
.wrap_err_with(|| output_changed_message!("aura --version", "invalid version"))?;
|
||||||
|
|
||||||
// Aura, since version 4.0.6, no longer needs sudo.
|
// Aura, since version 4.0.6, no longer needs sudo.
|
||||||
//
|
//
|
||||||
@@ -293,7 +286,7 @@ impl ArchPackageManager for Aura {
|
|||||||
let version_no_sudo = Version::new(4, 0, 6);
|
let version_no_sudo = Version::new(4, 0, 6);
|
||||||
|
|
||||||
if version >= version_no_sudo {
|
if version >= version_no_sudo {
|
||||||
let mut cmd = ctx.run_type().execute(&self.executable);
|
let mut cmd = ctx.execute(&self.executable);
|
||||||
cmd.arg("-Au")
|
cmd.arg("-Au")
|
||||||
.args(ctx.config().aura_aur_arguments().split_whitespace());
|
.args(ctx.config().aura_aur_arguments().split_whitespace());
|
||||||
if ctx.config().yes(Step::System) {
|
if ctx.config().yes(Step::System) {
|
||||||
@@ -301,7 +294,7 @@ impl ArchPackageManager for Aura {
|
|||||||
}
|
}
|
||||||
cmd.status_checked()?;
|
cmd.status_checked()?;
|
||||||
|
|
||||||
let mut cmd = ctx.run_type().execute(&self.executable);
|
let mut cmd = ctx.execute(&self.executable);
|
||||||
cmd.arg("-Syu")
|
cmd.arg("-Syu")
|
||||||
.args(ctx.config().aura_pacman_arguments().split_whitespace());
|
.args(ctx.config().aura_pacman_arguments().split_whitespace());
|
||||||
if ctx.config().yes(Step::System) {
|
if ctx.config().yes(Step::System) {
|
||||||
@@ -309,23 +302,18 @@ impl ArchPackageManager for Aura {
|
|||||||
}
|
}
|
||||||
cmd.status_checked()?;
|
cmd.status_checked()?;
|
||||||
} else {
|
} else {
|
||||||
let sudo = crate::utils::require_option(
|
let sudo = ctx.require_sudo()?;
|
||||||
ctx.sudo().as_ref(),
|
|
||||||
t!("Aura(<0.4.6) requires sudo installed to work with AUR packages").to_string(),
|
|
||||||
)?;
|
|
||||||
|
|
||||||
let mut cmd = ctx.run_type().execute(sudo);
|
let mut cmd = sudo.execute(ctx, &self.executable)?;
|
||||||
cmd.arg(&self.executable)
|
cmd.arg("-Au")
|
||||||
.arg("-Au")
|
|
||||||
.args(ctx.config().aura_aur_arguments().split_whitespace());
|
.args(ctx.config().aura_aur_arguments().split_whitespace());
|
||||||
if ctx.config().yes(Step::System) {
|
if ctx.config().yes(Step::System) {
|
||||||
cmd.arg("--noconfirm");
|
cmd.arg("--noconfirm");
|
||||||
}
|
}
|
||||||
cmd.status_checked()?;
|
cmd.status_checked()?;
|
||||||
|
|
||||||
let mut cmd = ctx.run_type().execute(sudo);
|
let mut cmd = sudo.execute(ctx, &self.executable)?;
|
||||||
cmd.arg(&self.executable)
|
cmd.arg("-Syu")
|
||||||
.arg("-Syu")
|
|
||||||
.args(ctx.config().aura_pacman_arguments().split_whitespace());
|
.args(ctx.config().aura_pacman_arguments().split_whitespace());
|
||||||
if ctx.config().yes(Step::System) {
|
if ctx.config().yes(Step::System) {
|
||||||
cmd.arg("--noconfirm");
|
cmd.arg("--noconfirm");
|
||||||
|
|||||||
@@ -1,16 +1,16 @@
|
|||||||
use crate::command::CommandExt;
|
use crate::command::CommandExt;
|
||||||
use crate::execution_context::ExecutionContext;
|
use crate::execution_context::ExecutionContext;
|
||||||
|
use crate::step::Step;
|
||||||
use crate::terminal::print_separator;
|
use crate::terminal::print_separator;
|
||||||
use crate::utils::{get_require_sudo_string, require_option};
|
|
||||||
use crate::Step;
|
|
||||||
use color_eyre::eyre::Result;
|
use color_eyre::eyre::Result;
|
||||||
use std::process::Command;
|
use rust_i18n::t;
|
||||||
|
|
||||||
pub fn upgrade_packages(ctx: &ExecutionContext) -> Result<()> {
|
pub fn upgrade_packages(ctx: &ExecutionContext) -> Result<()> {
|
||||||
let sudo = require_option(ctx.sudo().as_ref(), get_require_sudo_string())?;
|
|
||||||
print_separator(t!("DragonFly BSD Packages"));
|
print_separator(t!("DragonFly BSD Packages"));
|
||||||
let mut cmd = ctx.run_type().execute(sudo);
|
|
||||||
cmd.args(["/usr/local/sbin/pkg", "upgrade"]);
|
let sudo = ctx.require_sudo()?;
|
||||||
|
let mut cmd = sudo.execute(ctx, "/usr/local/sbin/pkg")?;
|
||||||
|
cmd.arg("upgrade");
|
||||||
if ctx.config().yes(Step::System) {
|
if ctx.config().yes(Step::System) {
|
||||||
cmd.arg("-y");
|
cmd.arg("-y");
|
||||||
}
|
}
|
||||||
@@ -18,19 +18,18 @@ pub fn upgrade_packages(ctx: &ExecutionContext) -> Result<()> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn audit_packages(ctx: &ExecutionContext) -> Result<()> {
|
pub fn audit_packages(ctx: &ExecutionContext) -> Result<()> {
|
||||||
let sudo = require_option(ctx.sudo().as_ref(), get_require_sudo_string())?;
|
|
||||||
|
|
||||||
print_separator(t!("DragonFly BSD Audit"));
|
print_separator(t!("DragonFly BSD Audit"));
|
||||||
|
|
||||||
#[allow(clippy::disallowed_methods)]
|
let sudo = ctx.require_sudo()?;
|
||||||
if !Command::new(sudo)
|
sudo.execute(ctx, "/usr/local/sbin/pkg")?
|
||||||
.args(["/usr/local/sbin/pkg", "audit", "-Fr"])
|
.args(["audit", "-Fr"])
|
||||||
.status()?
|
.status_checked_with(|status| {
|
||||||
.success()
|
if !status.success() {
|
||||||
{
|
println!(
|
||||||
println!(t!(
|
"{}",
|
||||||
"The package audit was successful, but vulnerable packages still remain on the system"
|
t!("The package audit was successful, but vulnerable packages still remain on the system")
|
||||||
));
|
);
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,28 +1,25 @@
|
|||||||
use crate::command::CommandExt;
|
use crate::command::CommandExt;
|
||||||
use crate::execution_context::ExecutionContext;
|
use crate::execution_context::ExecutionContext;
|
||||||
|
use crate::step::Step;
|
||||||
use crate::terminal::print_separator;
|
use crate::terminal::print_separator;
|
||||||
use crate::utils::{get_require_sudo_string, require_option};
|
use color_eyre::Result;
|
||||||
use crate::Step;
|
|
||||||
use color_eyre::eyre::Result;
|
|
||||||
use rust_i18n::t;
|
use rust_i18n::t;
|
||||||
use std::process::Command;
|
|
||||||
|
|
||||||
pub fn upgrade_freebsd(ctx: &ExecutionContext) -> Result<()> {
|
pub fn upgrade_freebsd(ctx: &ExecutionContext) -> Result<()> {
|
||||||
let sudo = require_option(ctx.sudo().as_ref(), get_require_sudo_string())?;
|
|
||||||
print_separator(t!("FreeBSD Update"));
|
print_separator(t!("FreeBSD Update"));
|
||||||
ctx.run_type()
|
|
||||||
.execute(sudo)
|
let sudo = ctx.require_sudo()?;
|
||||||
.args(["/usr/sbin/freebsd-update", "fetch", "install"])
|
sudo.execute(ctx, "/usr/sbin/freebsd-update")?
|
||||||
|
.args(["fetch", "install"])
|
||||||
.status_checked()
|
.status_checked()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn upgrade_packages(ctx: &ExecutionContext) -> Result<()> {
|
pub fn upgrade_packages(ctx: &ExecutionContext) -> Result<()> {
|
||||||
let sudo = require_option(ctx.sudo().as_ref(), get_require_sudo_string())?;
|
|
||||||
print_separator(t!("FreeBSD Packages"));
|
print_separator(t!("FreeBSD Packages"));
|
||||||
|
|
||||||
let mut command = ctx.run_type().execute(sudo);
|
let sudo = ctx.require_sudo()?;
|
||||||
|
let mut command = sudo.execute(ctx, "/usr/sbin/pkg")?;
|
||||||
command.args(["/usr/sbin/pkg", "upgrade"]);
|
command.arg("upgrade");
|
||||||
if ctx.config().yes(Step::System) {
|
if ctx.config().yes(Step::System) {
|
||||||
command.arg("-y");
|
command.arg("-y");
|
||||||
}
|
}
|
||||||
@@ -30,12 +27,10 @@ pub fn upgrade_packages(ctx: &ExecutionContext) -> Result<()> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn audit_packages(ctx: &ExecutionContext) -> Result<()> {
|
pub fn audit_packages(ctx: &ExecutionContext) -> Result<()> {
|
||||||
let sudo = require_option(ctx.sudo().as_ref(), get_require_sudo_string())?;
|
|
||||||
|
|
||||||
print_separator(t!("FreeBSD Audit"));
|
print_separator(t!("FreeBSD Audit"));
|
||||||
|
|
||||||
Command::new(sudo)
|
let sudo = ctx.require_sudo()?;
|
||||||
.args(["/usr/sbin/pkg", "audit", "-Fr"])
|
sudo.execute(ctx, "/usr/sbin/pkg")?
|
||||||
.status_checked()?;
|
.args(["audit", "-Fr"])
|
||||||
Ok(())
|
.status_checked()
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,11 +9,13 @@ use tracing::{debug, warn};
|
|||||||
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;
|
||||||
|
use crate::step::Step;
|
||||||
use crate::steps::generic::is_wsl;
|
use crate::steps::generic::is_wsl;
|
||||||
use crate::steps::os::archlinux;
|
use crate::steps::os::archlinux;
|
||||||
|
use crate::sudo::SudoExecuteOpts;
|
||||||
use crate::terminal::{print_separator, prompt_yesno};
|
use crate::terminal::{print_separator, prompt_yesno};
|
||||||
use crate::utils::{get_require_sudo_string, require, require_option, which, PathExt};
|
use crate::utils::{require, require_one, which, PathExt};
|
||||||
use crate::{Step, HOME_DIR};
|
use crate::HOME_DIR;
|
||||||
|
|
||||||
static OS_RELEASE_PATH: &str = "/etc/os-release";
|
static OS_RELEASE_PATH: &str = "/etc/os-release";
|
||||||
|
|
||||||
@@ -65,7 +67,7 @@ impl Distribution {
|
|||||||
Some("nobara") => Distribution::Nobara,
|
Some("nobara") => Distribution::Nobara,
|
||||||
Some("void") => Distribution::Void,
|
Some("void") => Distribution::Void,
|
||||||
Some("debian") | Some("pureos") | Some("Deepin") | Some("linuxmint") => Distribution::Debian,
|
Some("debian") | Some("pureos") | Some("Deepin") | Some("linuxmint") => Distribution::Debian,
|
||||||
Some("arch") | Some("manjaro-arm") | Some("garuda") | Some("artix") => Distribution::Arch,
|
Some("arch") | Some("manjaro-arm") | Some("garuda") | Some("artix") | Some("cachyos") => Distribution::Arch,
|
||||||
Some("solus") => Distribution::Solus,
|
Some("solus") => Distribution::Solus,
|
||||||
Some("gentoo") | Some("funtoo") => Distribution::Gentoo,
|
Some("gentoo") | Some("funtoo") => Distribution::Gentoo,
|
||||||
Some("exherbo") => Distribution::Exherbo,
|
Some("exherbo") => Distribution::Exherbo,
|
||||||
@@ -174,11 +176,9 @@ impl Distribution {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn update_bedrock(ctx: &ExecutionContext) -> Result<()> {
|
fn update_bedrock(ctx: &ExecutionContext) -> Result<()> {
|
||||||
let sudo = require_option(ctx.sudo().as_ref(), get_require_sudo_string())?;
|
let brl = require("brl")?;
|
||||||
|
|
||||||
ctx.run_type().execute(sudo).args(["brl", "update"]);
|
let output = Command::new(&brl).arg("list").output_checked_utf8()?;
|
||||||
|
|
||||||
let output = Command::new("brl").arg("list").output_checked_utf8()?;
|
|
||||||
debug!("brl list: {:?} {:?}", output.stdout, output.stderr);
|
debug!("brl list: {:?} {:?}", output.stdout, output.stderr);
|
||||||
|
|
||||||
for distribution in output.stdout.trim().lines() {
|
for distribution in output.stdout.trim().lines() {
|
||||||
@@ -199,53 +199,53 @@ fn update_bedrock(ctx: &ExecutionContext) -> Result<()> {
|
|||||||
|
|
||||||
fn upgrade_alpine_linux(ctx: &ExecutionContext) -> Result<()> {
|
fn upgrade_alpine_linux(ctx: &ExecutionContext) -> Result<()> {
|
||||||
let apk = require("apk")?;
|
let apk = require("apk")?;
|
||||||
let sudo = require_option(ctx.sudo().as_ref(), get_require_sudo_string())?;
|
let sudo = ctx.require_sudo()?;
|
||||||
|
|
||||||
ctx.run_type().execute(sudo).arg(&apk).arg("update").status_checked()?;
|
sudo.execute(ctx, &apk)?.arg("update").status_checked()?;
|
||||||
ctx.run_type().execute(sudo).arg(&apk).arg("upgrade").status_checked()
|
sudo.execute(ctx, &apk)?.arg("upgrade").status_checked()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn upgrade_chimera_linux(ctx: &ExecutionContext) -> Result<()> {
|
fn upgrade_chimera_linux(ctx: &ExecutionContext) -> Result<()> {
|
||||||
let apk = require("apk")?;
|
let apk = require("apk")?;
|
||||||
let sudo = require_option(ctx.sudo().as_ref(), get_require_sudo_string())?;
|
let sudo = ctx.require_sudo()?;
|
||||||
|
|
||||||
ctx.run_type().execute(sudo).arg(&apk).arg("update").status_checked()?;
|
sudo.execute(ctx, &apk)?.arg("update").status_checked()?;
|
||||||
ctx.run_type().execute(sudo).arg(&apk).arg("upgrade").status_checked()
|
sudo.execute(ctx, &apk)?.arg("upgrade").status_checked()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn upgrade_wolfi_linux(ctx: &ExecutionContext) -> Result<()> {
|
fn upgrade_wolfi_linux(ctx: &ExecutionContext) -> Result<()> {
|
||||||
let apk = require("apk")?;
|
let apk = require("apk")?;
|
||||||
let sudo = require_option(ctx.sudo().as_ref(), get_require_sudo_string())?;
|
let sudo = ctx.require_sudo()?;
|
||||||
|
|
||||||
ctx.run_type().execute(sudo).arg(&apk).arg("update").status_checked()?;
|
sudo.execute(ctx, &apk)?.arg("update").status_checked()?;
|
||||||
ctx.run_type().execute(sudo).arg(&apk).arg("upgrade").status_checked()
|
sudo.execute(ctx, &apk)?.arg("upgrade").status_checked()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn upgrade_redhat(ctx: &ExecutionContext) -> Result<()> {
|
fn upgrade_redhat(ctx: &ExecutionContext) -> Result<()> {
|
||||||
if let Some(bootc) = which("bootc") {
|
if let Some(bootc) = which("bootc") {
|
||||||
if ctx.config().bootc() {
|
if ctx.config().bootc() {
|
||||||
let sudo = require_option(ctx.sudo().as_ref(), get_require_sudo_string())?;
|
let sudo = ctx.require_sudo()?;
|
||||||
return ctx.run_type().execute(sudo).arg(&bootc).arg("upgrade").status_checked();
|
return sudo.execute(ctx, &bootc)?.arg("upgrade").status_checked();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
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.execute(ostree);
|
||||||
command.arg("upgrade");
|
command.arg("upgrade");
|
||||||
return command.status_checked();
|
return command.status_checked();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
let sudo = require_option(ctx.sudo().as_ref(), get_require_sudo_string())?;
|
let dnf = require_one(["dnf", "yum"])?;
|
||||||
let mut command = ctx.run_type().execute(sudo);
|
let sudo = ctx.require_sudo()?;
|
||||||
command
|
|
||||||
.arg(which("dnf").unwrap_or_else(|| Path::new("yum").to_path_buf()))
|
let mut command = sudo.execute(ctx, &dnf)?;
|
||||||
.arg(if ctx.config().redhat_distro_sync() {
|
command.arg(if ctx.config().redhat_distro_sync() {
|
||||||
"distro-sync"
|
"distro-sync"
|
||||||
} else {
|
} else {
|
||||||
"upgrade"
|
"upgrade"
|
||||||
});
|
});
|
||||||
|
|
||||||
if let Some(args) = ctx.config().dnf_arguments() {
|
if let Some(args) = ctx.config().dnf_arguments() {
|
||||||
command.args(args.split_whitespace());
|
command.args(args.split_whitespace());
|
||||||
@@ -260,11 +260,10 @@ fn upgrade_redhat(ctx: &ExecutionContext) -> Result<()> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn upgrade_nobara(ctx: &ExecutionContext) -> Result<()> {
|
fn upgrade_nobara(ctx: &ExecutionContext) -> Result<()> {
|
||||||
let sudo = require_option(ctx.sudo().as_ref(), get_require_sudo_string())?;
|
let dnf = require("dnf")?;
|
||||||
let pkg_manager = require("dnf")?;
|
let sudo = ctx.require_sudo()?;
|
||||||
|
|
||||||
let mut update_command = ctx.run_type().execute(sudo);
|
let mut update_command = sudo.execute(ctx, &dnf)?;
|
||||||
update_command.arg(&pkg_manager);
|
|
||||||
|
|
||||||
if ctx.config().yes(Step::System) {
|
if ctx.config().yes(Step::System) {
|
||||||
update_command.arg("-y");
|
update_command.arg("-y");
|
||||||
@@ -280,8 +279,7 @@ fn upgrade_nobara(ctx: &ExecutionContext) -> Result<()> {
|
|||||||
]);
|
]);
|
||||||
update_command.arg("--refresh").status_checked()?;
|
update_command.arg("--refresh").status_checked()?;
|
||||||
|
|
||||||
let mut upgrade_command = ctx.run_type().execute(sudo);
|
let mut upgrade_command = sudo.execute(ctx, &dnf)?;
|
||||||
upgrade_command.arg(&pkg_manager);
|
|
||||||
|
|
||||||
if ctx.config().yes(Step::System) {
|
if ctx.config().yes(Step::System) {
|
||||||
upgrade_command.arg("-y");
|
upgrade_command.arg("-y");
|
||||||
@@ -294,44 +292,44 @@ fn upgrade_nobara(ctx: &ExecutionContext) -> Result<()> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn upgrade_nilrt(ctx: &ExecutionContext) -> Result<()> {
|
fn upgrade_nilrt(ctx: &ExecutionContext) -> Result<()> {
|
||||||
let sudo = require_option(ctx.sudo().as_ref(), get_require_sudo_string())?;
|
|
||||||
let opkg = require("opkg")?;
|
let opkg = require("opkg")?;
|
||||||
|
let sudo = ctx.require_sudo()?;
|
||||||
|
|
||||||
ctx.run_type().execute(sudo).arg(&opkg).arg("update").status_checked()?;
|
sudo.execute(ctx, &opkg)?.arg("update").status_checked()?;
|
||||||
ctx.run_type().execute(sudo).arg(&opkg).arg("upgrade").status_checked()
|
sudo.execute(ctx, &opkg)?.arg("upgrade").status_checked()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn upgrade_fedora_immutable(ctx: &ExecutionContext) -> Result<()> {
|
fn upgrade_fedora_immutable(ctx: &ExecutionContext) -> Result<()> {
|
||||||
if let Some(bootc) = which("bootc") {
|
if let Some(bootc) = which("bootc") {
|
||||||
if ctx.config().bootc() {
|
if ctx.config().bootc() {
|
||||||
let sudo = require_option(ctx.sudo().as_ref(), get_require_sudo_string())?;
|
let sudo = ctx.require_sudo()?;
|
||||||
return ctx.run_type().execute(sudo).arg(&bootc).arg("upgrade").status_checked();
|
return sudo.execute(ctx, &bootc)?.arg("upgrade").status_checked();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let ostree = require("rpm-ostree")?;
|
let ostree = require("rpm-ostree")?;
|
||||||
let mut command = ctx.run_type().execute(ostree);
|
let mut command = ctx.execute(ostree);
|
||||||
command.arg("upgrade");
|
command.arg("upgrade");
|
||||||
command.status_checked()?;
|
command.status_checked()?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn upgrade_bedrock_strata(ctx: &ExecutionContext) -> Result<()> {
|
fn upgrade_bedrock_strata(ctx: &ExecutionContext) -> Result<()> {
|
||||||
let sudo = require_option(ctx.sudo().as_ref(), get_require_sudo_string())?;
|
let brl = require("brl")?;
|
||||||
ctx.run_type().execute(sudo).args(["brl", "update"]).status_checked()?;
|
let sudo = ctx.require_sudo()?;
|
||||||
|
|
||||||
|
sudo.execute(ctx, &brl)?.arg("update").status_checked()?;
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn upgrade_suse(ctx: &ExecutionContext) -> Result<()> {
|
fn upgrade_suse(ctx: &ExecutionContext) -> Result<()> {
|
||||||
let sudo = require_option(ctx.sudo().as_ref(), get_require_sudo_string())?;
|
let zypper = require("zypper")?;
|
||||||
ctx.run_type()
|
let sudo = ctx.require_sudo()?;
|
||||||
.execute(sudo)
|
|
||||||
.args(["zypper", "refresh"])
|
|
||||||
.status_checked()?;
|
|
||||||
|
|
||||||
let mut cmd = ctx.run_type().execute(sudo);
|
sudo.execute(ctx, &zypper)?.arg("refresh").status_checked()?;
|
||||||
cmd.arg("zypper");
|
|
||||||
|
let mut cmd = sudo.execute(ctx, &zypper)?;
|
||||||
cmd.arg(if ctx.config().suse_dup() {
|
cmd.arg(if ctx.config().suse_dup() {
|
||||||
"dist-upgrade"
|
"dist-upgrade"
|
||||||
} else {
|
} else {
|
||||||
@@ -347,14 +345,13 @@ fn upgrade_suse(ctx: &ExecutionContext) -> Result<()> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn upgrade_opensuse_tumbleweed(ctx: &ExecutionContext) -> Result<()> {
|
fn upgrade_opensuse_tumbleweed(ctx: &ExecutionContext) -> Result<()> {
|
||||||
let sudo = require_option(ctx.sudo().as_ref(), get_require_sudo_string())?;
|
let zypper = require("zypper")?;
|
||||||
ctx.run_type()
|
let sudo = ctx.require_sudo()?;
|
||||||
.execute(sudo)
|
|
||||||
.args(["zypper", "refresh"])
|
|
||||||
.status_checked()?;
|
|
||||||
|
|
||||||
let mut cmd = ctx.run_type().execute(sudo);
|
sudo.execute(ctx, &zypper)?.arg("refresh").status_checked()?;
|
||||||
cmd.args(["zypper", "dist-upgrade"]);
|
|
||||||
|
let mut cmd = sudo.execute(ctx, &zypper)?;
|
||||||
|
cmd.arg("dist-upgrade");
|
||||||
if ctx.config().yes(Step::System) {
|
if ctx.config().yes(Step::System) {
|
||||||
cmd.arg("-y");
|
cmd.arg("-y");
|
||||||
}
|
}
|
||||||
@@ -365,9 +362,10 @@ fn upgrade_opensuse_tumbleweed(ctx: &ExecutionContext) -> Result<()> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn upgrade_suse_micro(ctx: &ExecutionContext) -> Result<()> {
|
fn upgrade_suse_micro(ctx: &ExecutionContext) -> Result<()> {
|
||||||
let sudo = require_option(ctx.sudo().as_ref(), get_require_sudo_string())?;
|
let upd = require("transactional-update")?;
|
||||||
let mut cmd = ctx.run_type().execute(sudo);
|
let sudo = ctx.require_sudo()?;
|
||||||
cmd.arg("transactional-update");
|
|
||||||
|
let mut cmd = sudo.execute(ctx, &upd)?;
|
||||||
if ctx.config().yes(Step::System) {
|
if ctx.config().yes(Step::System) {
|
||||||
cmd.arg("-n");
|
cmd.arg("-n");
|
||||||
}
|
}
|
||||||
@@ -378,10 +376,12 @@ fn upgrade_suse_micro(ctx: &ExecutionContext) -> Result<()> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn upgrade_openmandriva(ctx: &ExecutionContext) -> Result<()> {
|
fn upgrade_openmandriva(ctx: &ExecutionContext) -> Result<()> {
|
||||||
let sudo = require_option(ctx.sudo().as_ref(), get_require_sudo_string())?;
|
let dnf = require("dnf")?;
|
||||||
let mut command = ctx.run_type().execute(sudo);
|
let sudo = ctx.require_sudo()?;
|
||||||
|
|
||||||
command.arg(which("dnf").unwrap()).arg("upgrade");
|
let mut command = sudo.execute(ctx, &dnf)?;
|
||||||
|
|
||||||
|
command.arg("upgrade");
|
||||||
|
|
||||||
if let Some(args) = ctx.config().dnf_arguments() {
|
if let Some(args) = ctx.config().dnf_arguments() {
|
||||||
command.args(args.split_whitespace());
|
command.args(args.split_whitespace());
|
||||||
@@ -397,10 +397,12 @@ fn upgrade_openmandriva(ctx: &ExecutionContext) -> Result<()> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn upgrade_pclinuxos(ctx: &ExecutionContext) -> Result<()> {
|
fn upgrade_pclinuxos(ctx: &ExecutionContext) -> Result<()> {
|
||||||
let sudo = require_option(ctx.sudo().as_ref(), get_require_sudo_string())?;
|
let apt_get = require("apt-get")?;
|
||||||
let mut command_update = ctx.run_type().execute(sudo);
|
let sudo = ctx.require_sudo()?;
|
||||||
|
|
||||||
command_update.arg(which("apt-get").unwrap()).arg("update");
|
let mut command_update = sudo.execute(ctx, &apt_get)?;
|
||||||
|
|
||||||
|
command_update.arg("update");
|
||||||
|
|
||||||
if let Some(args) = ctx.config().dnf_arguments() {
|
if let Some(args) = ctx.config().dnf_arguments() {
|
||||||
command_update.args(args.split_whitespace());
|
command_update.args(args.split_whitespace());
|
||||||
@@ -412,8 +414,7 @@ fn upgrade_pclinuxos(ctx: &ExecutionContext) -> Result<()> {
|
|||||||
|
|
||||||
command_update.status_checked()?;
|
command_update.status_checked()?;
|
||||||
|
|
||||||
let mut cmd = ctx.run_type().execute(sudo);
|
let mut cmd = sudo.execute(ctx, &apt_get)?;
|
||||||
cmd.arg(which("apt-get").unwrap());
|
|
||||||
cmd.arg("dist-upgrade");
|
cmd.arg("dist-upgrade");
|
||||||
if ctx.config().yes(Step::System) {
|
if ctx.config().yes(Step::System) {
|
||||||
cmd.arg("-y");
|
cmd.arg("-y");
|
||||||
@@ -426,14 +427,14 @@ fn upgrade_pclinuxos(ctx: &ExecutionContext) -> Result<()> {
|
|||||||
fn upgrade_vanilla(ctx: &ExecutionContext) -> Result<()> {
|
fn upgrade_vanilla(ctx: &ExecutionContext) -> Result<()> {
|
||||||
let apx = require("apx")?;
|
let apx = require("apx")?;
|
||||||
|
|
||||||
let mut update = ctx.run_type().execute(&apx);
|
let mut update = ctx.execute(&apx);
|
||||||
update.args(["update", "--all"]);
|
update.args(["update", "--all"]);
|
||||||
if ctx.config().yes(Step::System) {
|
if ctx.config().yes(Step::System) {
|
||||||
update.arg("-y");
|
update.arg("-y");
|
||||||
}
|
}
|
||||||
update.status_checked()?;
|
update.status_checked()?;
|
||||||
|
|
||||||
let mut upgrade = ctx.run_type().execute(&apx);
|
let mut upgrade = ctx.execute(&apx);
|
||||||
update.args(["upgrade", "--all"]);
|
update.args(["upgrade", "--all"]);
|
||||||
if ctx.config().yes(Step::System) {
|
if ctx.config().yes(Step::System) {
|
||||||
upgrade.arg("-y");
|
upgrade.arg("-y");
|
||||||
@@ -444,16 +445,18 @@ fn upgrade_vanilla(ctx: &ExecutionContext) -> Result<()> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn upgrade_void(ctx: &ExecutionContext) -> Result<()> {
|
fn upgrade_void(ctx: &ExecutionContext) -> Result<()> {
|
||||||
let sudo = require_option(ctx.sudo().as_ref(), get_require_sudo_string())?;
|
let xbps = require("xbps-install")?;
|
||||||
let mut command = ctx.run_type().execute(sudo);
|
let sudo = ctx.require_sudo()?;
|
||||||
command.args(["xbps-install", "-Su", "xbps"]);
|
|
||||||
|
let mut command = sudo.execute(ctx, &xbps)?;
|
||||||
|
command.args(["-Su", "xbps"]);
|
||||||
if ctx.config().yes(Step::System) {
|
if ctx.config().yes(Step::System) {
|
||||||
command.arg("-y");
|
command.arg("-y");
|
||||||
}
|
}
|
||||||
command.status_checked()?;
|
command.status_checked()?;
|
||||||
|
|
||||||
let mut command = ctx.run_type().execute(sudo);
|
let mut command = sudo.execute(ctx, &xbps)?;
|
||||||
command.args(["xbps-install", "-u"]);
|
command.arg("-u");
|
||||||
if ctx.config().yes(Step::System) {
|
if ctx.config().yes(Step::System) {
|
||||||
command.arg("-y");
|
command.arg("-y");
|
||||||
}
|
}
|
||||||
@@ -463,25 +466,20 @@ fn upgrade_void(ctx: &ExecutionContext) -> Result<()> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn upgrade_gentoo(ctx: &ExecutionContext) -> Result<()> {
|
fn upgrade_gentoo(ctx: &ExecutionContext) -> Result<()> {
|
||||||
let run_type = ctx.run_type();
|
let emerge = require("emerge")?;
|
||||||
|
let sudo = ctx.require_sudo()?;
|
||||||
|
|
||||||
let sudo = require_option(ctx.sudo().as_ref(), get_require_sudo_string())?;
|
|
||||||
if let Some(layman) = which("layman") {
|
if let Some(layman) = which("layman") {
|
||||||
run_type
|
sudo.execute(ctx, &layman)?.args(["-s", "ALL"]).status_checked()?;
|
||||||
.execute(sudo)
|
|
||||||
.arg(layman)
|
|
||||||
.args(["-s", "ALL"])
|
|
||||||
.status_checked()?;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
println!("{}", t!("Syncing portage"));
|
println!("{}", t!("Syncing portage"));
|
||||||
if let Some(ego) = which("ego") {
|
if let Some(ego) = which("ego") {
|
||||||
// The Funtoo team doesn't reccomend running both ego sync and emerge --sync
|
// The Funtoo team doesn't recommend running both ego sync and emerge --sync
|
||||||
run_type.execute(sudo).arg(ego).arg("sync").status_checked()?;
|
sudo.execute(ctx, &ego)?.arg("sync").status_checked()?;
|
||||||
} else {
|
} else {
|
||||||
run_type
|
sudo.execute(ctx, &emerge)?
|
||||||
.execute(sudo)
|
.arg("--sync")
|
||||||
.args(["emerge", "--sync"])
|
|
||||||
.args(
|
.args(
|
||||||
ctx.config()
|
ctx.config()
|
||||||
.emerge_sync_flags()
|
.emerge_sync_flags()
|
||||||
@@ -492,12 +490,10 @@ fn upgrade_gentoo(ctx: &ExecutionContext) -> Result<()> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if let Some(eix_update) = which("eix-update") {
|
if let Some(eix_update) = which("eix-update") {
|
||||||
run_type.execute(sudo).arg(eix_update).status_checked()?;
|
sudo.execute(ctx, &eix_update)?.status_checked()?;
|
||||||
}
|
}
|
||||||
|
|
||||||
run_type
|
sudo.execute(ctx, &emerge)?
|
||||||
.execute(sudo)
|
|
||||||
.arg("emerge")
|
|
||||||
.args(
|
.args(
|
||||||
ctx.config()
|
ctx.config()
|
||||||
.emerge_update_flags()
|
.emerge_update_flags()
|
||||||
@@ -509,49 +505,51 @@ fn upgrade_gentoo(ctx: &ExecutionContext) -> Result<()> {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn upgrade_debian(ctx: &ExecutionContext) -> Result<()> {
|
enum AptKind {
|
||||||
let apt = which("apt-fast")
|
AptFast,
|
||||||
.or_else(|| {
|
Mist,
|
||||||
if which("mist").is_some() {
|
Nala,
|
||||||
Some(PathBuf::from("mist"))
|
AptGet,
|
||||||
} else {
|
}
|
||||||
None
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.or_else(|| {
|
|
||||||
if Path::new("/usr/bin/nala").exists() {
|
|
||||||
Some(Path::new("/usr/bin/nala").to_path_buf())
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.unwrap_or_else(|| PathBuf::from("apt-get"));
|
|
||||||
|
|
||||||
let is_mist = apt.ends_with("mist");
|
fn detect_apt() -> Result<(AptKind, PathBuf)> {
|
||||||
let is_nala = apt.ends_with("nala");
|
use AptKind::*;
|
||||||
|
|
||||||
|
if let Some(apt_fast) = which("apt-fast") {
|
||||||
|
Ok((AptFast, apt_fast))
|
||||||
|
} else if let Some(mist) = which("mist") {
|
||||||
|
Ok((Mist, mist))
|
||||||
|
} else if Path::new("/usr/bin/nala").exists() {
|
||||||
|
Ok((Nala, Path::new("/usr/bin/nala").to_path_buf()))
|
||||||
|
} else {
|
||||||
|
Ok((AptGet, require("apt-get")?))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn upgrade_debian(ctx: &ExecutionContext) -> Result<()> {
|
||||||
|
use AptKind::*;
|
||||||
|
|
||||||
|
let (kind, apt) = detect_apt()?;
|
||||||
|
|
||||||
// MIST does not require `sudo`
|
// MIST does not require `sudo`
|
||||||
if is_mist {
|
if matches!(kind, Mist) {
|
||||||
ctx.run_type().execute(&apt).arg("update").status_checked()?;
|
ctx.execute(&apt).arg("update").status_checked()?;
|
||||||
ctx.run_type().execute(&apt).arg("upgrade").status_checked()?;
|
ctx.execute(&apt).arg("upgrade").status_checked()?;
|
||||||
|
|
||||||
// Simply return as MIST does not have `clean` and `autoremove`
|
// Simply return as MIST does not have `clean` and `autoremove`
|
||||||
// subcommands, neither the `-y` option (for now maybe?).
|
// subcommands, neither the `-y` option (for now maybe?).
|
||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
|
|
||||||
let sudo = require_option(ctx.sudo().as_ref(), get_require_sudo_string())?;
|
let sudo = ctx.require_sudo()?;
|
||||||
if !is_nala {
|
if !matches!(kind, Nala) {
|
||||||
ctx.run_type()
|
sudo.execute(ctx, &apt)?
|
||||||
.execute(sudo)
|
|
||||||
.arg(&apt)
|
|
||||||
.arg("update")
|
.arg("update")
|
||||||
.status_checked_with_codes(&[0, 100])?;
|
.status_checked_with_codes(&[0, 100])?;
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut command = ctx.run_type().execute(sudo);
|
let mut command = sudo.execute(ctx, &apt)?;
|
||||||
command.arg(&apt);
|
if matches!(kind, Nala) {
|
||||||
if is_nala {
|
|
||||||
command.arg("upgrade");
|
command.arg("upgrade");
|
||||||
} else {
|
} else {
|
||||||
command.arg("dist-upgrade");
|
command.arg("dist-upgrade");
|
||||||
@@ -565,10 +563,10 @@ fn upgrade_debian(ctx: &ExecutionContext) -> Result<()> {
|
|||||||
command.status_checked()?;
|
command.status_checked()?;
|
||||||
|
|
||||||
if ctx.config().cleanup() {
|
if ctx.config().cleanup() {
|
||||||
ctx.run_type().execute(sudo).arg(&apt).arg("clean").status_checked()?;
|
sudo.execute(ctx, &apt)?.arg("clean").status_checked()?;
|
||||||
|
|
||||||
let mut command = ctx.run_type().execute(sudo);
|
let mut command = sudo.execute(ctx, &apt)?;
|
||||||
command.arg(&apt).arg("autoremove");
|
command.arg("autoremove");
|
||||||
if ctx.config().yes(Step::System) {
|
if ctx.config().yes(Step::System) {
|
||||||
command.arg("-y");
|
command.arg("-y");
|
||||||
}
|
}
|
||||||
@@ -583,20 +581,32 @@ pub fn run_deb_get(ctx: &ExecutionContext) -> Result<()> {
|
|||||||
|
|
||||||
print_separator("deb-get");
|
print_separator("deb-get");
|
||||||
|
|
||||||
ctx.run_type().execute(&deb_get).arg("update").status_checked()?;
|
ctx.execute(&deb_get).arg("update").status_checked()?;
|
||||||
ctx.run_type().execute(&deb_get).arg("upgrade").status_checked()?;
|
ctx.execute(&deb_get)
|
||||||
|
.arg("upgrade")
|
||||||
|
// Since the `apt` step already updates all other apt packages, don't check for updates
|
||||||
|
// to all packages here. This does suboptimally check for updates for deb-get packages
|
||||||
|
// that apt can update (that were installed via a repository), but that is only a few,
|
||||||
|
// and there's nothing we can do about that.
|
||||||
|
.arg("--dg-only")
|
||||||
|
.status_checked()?;
|
||||||
|
|
||||||
if ctx.config().cleanup() {
|
if ctx.config().cleanup() {
|
||||||
ctx.run_type().execute(&deb_get).arg("clean").status_checked()?;
|
let output = ctx.execute(&deb_get).arg("clean").output_checked()?;
|
||||||
|
// Swallow the output, as it's very noisy and not useful.
|
||||||
|
// The output is automatically printed as part of `output_checked` when an error occurs.
|
||||||
|
println!("{}", t!("<output from `deb-get clean` omitted>"));
|
||||||
|
debug!("`deb-get clean` output: {output:?}");
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn upgrade_solus(ctx: &ExecutionContext) -> Result<()> {
|
fn upgrade_solus(ctx: &ExecutionContext) -> Result<()> {
|
||||||
let sudo = require_option(ctx.sudo().as_ref(), get_require_sudo_string())?;
|
let eopkg = require("eopkg")?;
|
||||||
let mut cmd = ctx.run_type().execute(sudo);
|
let sudo = ctx.require_sudo()?;
|
||||||
cmd.arg("eopkg");
|
|
||||||
|
let mut cmd = sudo.execute(ctx, &eopkg)?;
|
||||||
if ctx.config().yes(Step::System) {
|
if ctx.config().yes(Step::System) {
|
||||||
cmd.arg("-y");
|
cmd.arg("-y");
|
||||||
}
|
}
|
||||||
@@ -610,7 +620,7 @@ pub fn run_am(ctx: &ExecutionContext) -> Result<()> {
|
|||||||
|
|
||||||
print_separator("AM");
|
print_separator("AM");
|
||||||
|
|
||||||
let mut am = ctx.run_type().execute(am);
|
let mut am = ctx.execute(am);
|
||||||
|
|
||||||
if ctx.config().yes(Step::AM) {
|
if ctx.config().yes(Step::AM) {
|
||||||
am.arg("-U");
|
am.arg("-U");
|
||||||
@@ -626,7 +636,7 @@ pub fn run_appman(ctx: &ExecutionContext) -> Result<()> {
|
|||||||
|
|
||||||
print_separator("appman");
|
print_separator("appman");
|
||||||
|
|
||||||
ctx.run_type().execute(appman).arg("-u").status_checked()
|
ctx.execute(appman).arg("-u").status_checked()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn run_pacdef(ctx: &ExecutionContext) -> Result<()> {
|
pub fn run_pacdef(ctx: &ExecutionContext) -> Result<()> {
|
||||||
@@ -634,12 +644,12 @@ pub fn run_pacdef(ctx: &ExecutionContext) -> Result<()> {
|
|||||||
|
|
||||||
print_separator("pacdef");
|
print_separator("pacdef");
|
||||||
|
|
||||||
let output = ctx.run_type().execute(&pacdef).arg("version").output_checked()?;
|
let output = ctx.execute(&pacdef).arg("version").output_checked()?;
|
||||||
let string = String::from_utf8(output.stdout)?;
|
let string = String::from_utf8(output.stdout)?;
|
||||||
let new_version = string.contains("version: 1");
|
let new_version = string.contains("version: 1");
|
||||||
|
|
||||||
if new_version {
|
if new_version {
|
||||||
let mut cmd = ctx.run_type().execute(&pacdef);
|
let mut cmd = ctx.execute(&pacdef);
|
||||||
cmd.args(["package", "sync"]);
|
cmd.args(["package", "sync"]);
|
||||||
if ctx.config().yes(Step::System) {
|
if ctx.config().yes(Step::System) {
|
||||||
cmd.arg("--noconfirm");
|
cmd.arg("--noconfirm");
|
||||||
@@ -647,12 +657,9 @@ pub fn run_pacdef(ctx: &ExecutionContext) -> Result<()> {
|
|||||||
cmd.status_checked()?;
|
cmd.status_checked()?;
|
||||||
|
|
||||||
println!();
|
println!();
|
||||||
ctx.run_type()
|
ctx.execute(&pacdef).args(["package", "review"]).status_checked()?;
|
||||||
.execute(&pacdef)
|
|
||||||
.args(["package", "review"])
|
|
||||||
.status_checked()?;
|
|
||||||
} else {
|
} else {
|
||||||
let mut cmd = ctx.run_type().execute(&pacdef);
|
let mut cmd = ctx.execute(&pacdef);
|
||||||
cmd.arg("sync");
|
cmd.arg("sync");
|
||||||
if ctx.config().yes(Step::System) {
|
if ctx.config().yes(Step::System) {
|
||||||
cmd.arg("--noconfirm");
|
cmd.arg("--noconfirm");
|
||||||
@@ -661,7 +668,7 @@ pub fn run_pacdef(ctx: &ExecutionContext) -> Result<()> {
|
|||||||
cmd.status_checked()?;
|
cmd.status_checked()?;
|
||||||
|
|
||||||
println!();
|
println!();
|
||||||
ctx.run_type().execute(&pacdef).arg("review").status_checked()?;
|
ctx.execute(&pacdef).arg("review").status_checked()?;
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
@@ -671,8 +678,8 @@ pub fn run_pacstall(ctx: &ExecutionContext) -> Result<()> {
|
|||||||
|
|
||||||
print_separator("Pacstall");
|
print_separator("Pacstall");
|
||||||
|
|
||||||
let mut update_cmd = ctx.run_type().execute(&pacstall);
|
let mut update_cmd = ctx.execute(&pacstall);
|
||||||
let mut upgrade_cmd = ctx.run_type().execute(pacstall);
|
let mut upgrade_cmd = ctx.execute(pacstall);
|
||||||
|
|
||||||
if ctx.config().yes(Step::Pacstall) {
|
if ctx.config().yes(Step::Pacstall) {
|
||||||
update_cmd.arg("-P");
|
update_cmd.arg("-P");
|
||||||
@@ -683,6 +690,32 @@ pub fn run_pacstall(ctx: &ExecutionContext) -> Result<()> {
|
|||||||
upgrade_cmd.arg("-Up").status_checked()
|
upgrade_cmd.arg("-Up").status_checked()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn run_pkgfile(ctx: &ExecutionContext) -> Result<()> {
|
||||||
|
let pkgfile = require("pkgfile")?;
|
||||||
|
|
||||||
|
print_separator("pkgfile");
|
||||||
|
|
||||||
|
let sudo = ctx.require_sudo()?;
|
||||||
|
sudo.execute(ctx, pkgfile)?.arg("--update").status_checked()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn run_mandb(ctx: &ExecutionContext) -> Result<()> {
|
||||||
|
let mandb = require("mandb")?;
|
||||||
|
|
||||||
|
if !ctx.config().enable_mandb() {
|
||||||
|
return Err(SkipStep(t!("ManDB isn't enabled").to_string()).into());
|
||||||
|
}
|
||||||
|
|
||||||
|
print_separator(t!("System Manuals"));
|
||||||
|
|
||||||
|
let sudo = ctx.require_sudo()?;
|
||||||
|
sudo.execute(ctx, &mandb)?.status_checked()?;
|
||||||
|
|
||||||
|
print_separator(t!("User Manuals"));
|
||||||
|
|
||||||
|
ctx.execute(&mandb).arg("--user-db").status_checked()
|
||||||
|
}
|
||||||
|
|
||||||
pub fn run_packer_nu(ctx: &ExecutionContext) -> Result<()> {
|
pub fn run_packer_nu(ctx: &ExecutionContext) -> Result<()> {
|
||||||
let nu = require("nu")?;
|
let nu = require("nu")?;
|
||||||
let packer_home = HOME_DIR.join(".local/share/nushell/packer");
|
let packer_home = HOME_DIR.join(".local/share/nushell/packer");
|
||||||
@@ -691,8 +724,7 @@ pub fn run_packer_nu(ctx: &ExecutionContext) -> Result<()> {
|
|||||||
|
|
||||||
print_separator("packer.nu");
|
print_separator("packer.nu");
|
||||||
|
|
||||||
ctx.run_type()
|
ctx.execute(nu)
|
||||||
.execute(nu)
|
|
||||||
.env("PWD", "/")
|
.env("PWD", "/")
|
||||||
.env("NU_PACKER_HOME", packer_home)
|
.env("NU_PACKER_HOME", packer_home)
|
||||||
.args([
|
.args([
|
||||||
@@ -703,9 +735,11 @@ pub fn run_packer_nu(ctx: &ExecutionContext) -> Result<()> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn upgrade_clearlinux(ctx: &ExecutionContext) -> Result<()> {
|
fn upgrade_clearlinux(ctx: &ExecutionContext) -> Result<()> {
|
||||||
let sudo = require_option(ctx.sudo().as_ref(), get_require_sudo_string())?;
|
let swupd = require("swupd")?;
|
||||||
let mut cmd = ctx.run_type().execute(sudo);
|
let sudo = ctx.require_sudo()?;
|
||||||
cmd.args(["swupd", "update"]);
|
|
||||||
|
let mut cmd = sudo.execute(ctx, &swupd)?;
|
||||||
|
cmd.arg("update");
|
||||||
if ctx.config().yes(Step::System) {
|
if ctx.config().yes(Step::System) {
|
||||||
cmd.arg("--assume=yes");
|
cmd.arg("--assume=yes");
|
||||||
}
|
}
|
||||||
@@ -715,38 +749,36 @@ fn upgrade_clearlinux(ctx: &ExecutionContext) -> Result<()> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn upgrade_exherbo(ctx: &ExecutionContext) -> Result<()> {
|
fn upgrade_exherbo(ctx: &ExecutionContext) -> Result<()> {
|
||||||
let sudo = require_option(ctx.sudo().as_ref(), get_require_sudo_string())?;
|
let cave = require("cave")?;
|
||||||
ctx.run_type().execute(sudo).args(["cave", "sync"]).status_checked()?;
|
let eclectic = require("eclectic")?;
|
||||||
|
let sudo = ctx.require_sudo()?;
|
||||||
|
|
||||||
ctx.run_type()
|
sudo.execute(ctx, &cave)?.arg("sync").status_checked()?;
|
||||||
.execute(sudo)
|
|
||||||
.args(["cave", "resolve", "world", "-c1", "-Cs", "-km", "-Km", "-x"])
|
sudo.execute(ctx, &cave)?
|
||||||
|
.args(["resolve", "world", "-c1", "-Cs", "-km", "-Km", "-x"])
|
||||||
.status_checked()?;
|
.status_checked()?;
|
||||||
|
|
||||||
if ctx.config().cleanup() {
|
if ctx.config().cleanup() {
|
||||||
ctx.run_type()
|
sudo.execute(ctx, &cave)?.args(["purge", "-x"]).status_checked()?;
|
||||||
.execute(sudo)
|
|
||||||
.args(["cave", "purge", "-x"])
|
|
||||||
.status_checked()?;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ctx.run_type()
|
sudo.execute(ctx, &cave)?
|
||||||
.execute(sudo)
|
.args(["fix-linkage", "-x", "--", "-Cs"])
|
||||||
.args(["cave", "fix-linkage", "-x", "--", "-Cs"])
|
|
||||||
.status_checked()?;
|
.status_checked()?;
|
||||||
|
|
||||||
ctx.run_type()
|
sudo.execute(ctx, &eclectic)?
|
||||||
.execute(sudo)
|
.args(["config", "interactive"])
|
||||||
.args(["eclectic", "config", "interactive"])
|
|
||||||
.status_checked()?;
|
.status_checked()?;
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn upgrade_nixos(ctx: &ExecutionContext) -> Result<()> {
|
fn upgrade_nixos(ctx: &ExecutionContext) -> Result<()> {
|
||||||
let sudo = require_option(ctx.sudo().as_ref(), get_require_sudo_string())?;
|
let sudo = ctx.require_sudo()?;
|
||||||
let mut command = ctx.run_type().execute(sudo);
|
|
||||||
command.args(["/run/current-system/sw/bin/nixos-rebuild", "switch", "--upgrade"]);
|
let mut command = sudo.execute(ctx, "/run/current-system/sw/bin/nixos-rebuild")?;
|
||||||
|
command.args(["switch", "--upgrade"]);
|
||||||
|
|
||||||
if let Some(args) = ctx.config().nix_arguments() {
|
if let Some(args) = ctx.config().nix_arguments() {
|
||||||
command.args(args.split_whitespace());
|
command.args(args.split_whitespace());
|
||||||
@@ -754,9 +786,8 @@ fn upgrade_nixos(ctx: &ExecutionContext) -> Result<()> {
|
|||||||
command.status_checked()?;
|
command.status_checked()?;
|
||||||
|
|
||||||
if ctx.config().cleanup() {
|
if ctx.config().cleanup() {
|
||||||
ctx.run_type()
|
sudo.execute(ctx, "/run/current-system/sw/bin/nix-collect-garbage")?
|
||||||
.execute(sudo)
|
.arg("-d")
|
||||||
.args(["/run/current-system/sw/bin/nix-collect-garbage", "-d"])
|
|
||||||
.status_checked()?;
|
.status_checked()?;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -770,16 +801,14 @@ fn upgrade_neon(ctx: &ExecutionContext) -> Result<()> {
|
|||||||
// seems rare
|
// seems rare
|
||||||
// if that comes up we need to create a Distribution::PackageKit or some such
|
// if that comes up we need to create a Distribution::PackageKit or some such
|
||||||
|
|
||||||
let sudo = require_option(ctx.sudo().as_ref(), get_require_sudo_string())?;
|
let pkcon = require("pkcon")?;
|
||||||
let pkcon = which("pkcon").unwrap();
|
let sudo = ctx.require_sudo()?;
|
||||||
|
|
||||||
// pkcon ignores update with update and refresh provided together
|
// pkcon ignores update with update and refresh provided together
|
||||||
ctx.run_type()
|
sudo.execute(ctx, &pkcon)?.arg("refresh").status_checked()?;
|
||||||
.execute(sudo)
|
|
||||||
.arg(&pkcon)
|
let mut exe = sudo.execute(ctx, &pkcon)?;
|
||||||
.arg("refresh")
|
let cmd = exe.arg("update");
|
||||||
.status_checked()?;
|
|
||||||
let mut exe = ctx.run_type().execute(sudo);
|
|
||||||
let cmd = exe.arg(&pkcon).arg("update");
|
|
||||||
if ctx.config().yes(Step::System) {
|
if ctx.config().yes(Step::System) {
|
||||||
cmd.arg("-y");
|
cmd.arg("-y");
|
||||||
}
|
}
|
||||||
@@ -806,26 +835,8 @@ fn should_skip_needrestart() -> Result<()> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if matches!(distribution, Distribution::Debian) {
|
if matches!(distribution, Distribution::Debian) {
|
||||||
let apt = which("apt-fast")
|
let (apt_kind, _) = detect_apt()?;
|
||||||
.or_else(|| {
|
if matches!(apt_kind, AptKind::Nala) {
|
||||||
if which("mist").is_some() {
|
|
||||||
Some(PathBuf::from("mist"))
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.or_else(|| {
|
|
||||||
if Path::new("/usr/bin/nala").exists() {
|
|
||||||
Some(Path::new("/usr/bin/nala").to_path_buf())
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.unwrap_or_else(|| PathBuf::from("apt-get"));
|
|
||||||
|
|
||||||
let is_nala = apt.ends_with("nala");
|
|
||||||
|
|
||||||
if is_nala {
|
|
||||||
return Err(SkipStep(String::from(msg)).into());
|
return Err(SkipStep(String::from(msg)).into());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -834,14 +845,14 @@ fn should_skip_needrestart() -> Result<()> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn run_needrestart(ctx: &ExecutionContext) -> Result<()> {
|
pub fn run_needrestart(ctx: &ExecutionContext) -> Result<()> {
|
||||||
let sudo = require_option(ctx.sudo().as_ref(), get_require_sudo_string())?;
|
|
||||||
let needrestart = require("needrestart")?;
|
let needrestart = require("needrestart")?;
|
||||||
|
|
||||||
should_skip_needrestart()?;
|
should_skip_needrestart()?;
|
||||||
|
|
||||||
print_separator(t!("Check for needed restarts"));
|
print_separator(t!("Check for needed restarts"));
|
||||||
|
|
||||||
ctx.run_type().execute(sudo).arg(needrestart).status_checked()?;
|
let sudo = ctx.require_sudo()?;
|
||||||
|
sudo.execute(ctx, &needrestart)?.status_checked()?;
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
@@ -855,12 +866,9 @@ pub fn run_fwupdmgr(ctx: &ExecutionContext) -> Result<()> {
|
|||||||
|
|
||||||
print_separator(t!("Firmware upgrades"));
|
print_separator(t!("Firmware upgrades"));
|
||||||
|
|
||||||
ctx.run_type()
|
ctx.execute(&fwupdmgr).arg("refresh").status_checked_with_codes(&[2])?;
|
||||||
.execute(&fwupdmgr)
|
|
||||||
.arg("refresh")
|
|
||||||
.status_checked_with_codes(&[2])?;
|
|
||||||
|
|
||||||
let mut updmgr = ctx.run_type().execute(&fwupdmgr);
|
let mut updmgr = ctx.execute(&fwupdmgr);
|
||||||
|
|
||||||
if ctx.config().firmware_upgrade() {
|
if ctx.config().firmware_upgrade() {
|
||||||
updmgr.arg("update");
|
updmgr.arg("update");
|
||||||
@@ -875,60 +883,52 @@ pub fn run_fwupdmgr(ctx: &ExecutionContext) -> Result<()> {
|
|||||||
|
|
||||||
pub fn run_flatpak(ctx: &ExecutionContext) -> Result<()> {
|
pub fn run_flatpak(ctx: &ExecutionContext) -> Result<()> {
|
||||||
let flatpak = require("flatpak")?;
|
let flatpak = require("flatpak")?;
|
||||||
let sudo = require_option(ctx.sudo().as_ref(), get_require_sudo_string())?;
|
|
||||||
let cleanup = ctx.config().cleanup();
|
let cleanup = ctx.config().cleanup();
|
||||||
let yes = ctx.config().yes(Step::Flatpak);
|
let yes = ctx.config().yes(Step::Flatpak);
|
||||||
let run_type = ctx.run_type();
|
|
||||||
print_separator("Flatpak User Packages");
|
print_separator("Flatpak User Packages");
|
||||||
|
|
||||||
let mut update_args = vec!["update", "--user"];
|
let mut update_args = vec!["update", "--user"];
|
||||||
if yes {
|
if yes {
|
||||||
update_args.push("-y");
|
update_args.push("-y");
|
||||||
}
|
}
|
||||||
run_type.execute(&flatpak).args(&update_args).status_checked()?;
|
ctx.execute(&flatpak).args(&update_args).status_checked()?;
|
||||||
|
|
||||||
if cleanup {
|
if cleanup {
|
||||||
let mut cleanup_args = vec!["uninstall", "--user", "--unused"];
|
let mut cleanup_args = vec!["uninstall", "--user", "--unused"];
|
||||||
if yes {
|
if yes {
|
||||||
cleanup_args.push("-y");
|
cleanup_args.push("-y");
|
||||||
}
|
}
|
||||||
run_type.execute(&flatpak).args(&cleanup_args).status_checked()?;
|
ctx.execute(&flatpak).args(&cleanup_args).status_checked()?;
|
||||||
}
|
}
|
||||||
|
|
||||||
print_separator(t!("Flatpak System Packages"));
|
print_separator(t!("Flatpak System Packages"));
|
||||||
if ctx.config().flatpak_use_sudo() || std::env::var("SSH_CLIENT").is_ok() {
|
if ctx.config().flatpak_use_sudo() || std::env::var("SSH_CLIENT").is_ok() {
|
||||||
|
let sudo = ctx.require_sudo()?;
|
||||||
let mut update_args = vec!["update", "--system"];
|
let mut update_args = vec!["update", "--system"];
|
||||||
if yes {
|
if yes {
|
||||||
update_args.push("-y");
|
update_args.push("-y");
|
||||||
}
|
}
|
||||||
run_type
|
sudo.execute(ctx, &flatpak)?.args(&update_args).status_checked()?;
|
||||||
.execute(sudo)
|
|
||||||
.arg(&flatpak)
|
|
||||||
.args(&update_args)
|
|
||||||
.status_checked()?;
|
|
||||||
if cleanup {
|
if cleanup {
|
||||||
let mut cleanup_args = vec!["uninstall", "--system", "--unused"];
|
let mut cleanup_args = vec!["uninstall", "--system", "--unused"];
|
||||||
if yes {
|
if yes {
|
||||||
cleanup_args.push("-y");
|
cleanup_args.push("-y");
|
||||||
}
|
}
|
||||||
run_type
|
sudo.execute(ctx, &flatpak)?.args(&cleanup_args).status_checked()?;
|
||||||
.execute(sudo)
|
|
||||||
.arg(flatpak)
|
|
||||||
.args(&cleanup_args)
|
|
||||||
.status_checked()?;
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
let mut update_args = vec!["update", "--system"];
|
let mut update_args = vec!["update", "--system"];
|
||||||
if yes {
|
if yes {
|
||||||
update_args.push("-y");
|
update_args.push("-y");
|
||||||
}
|
}
|
||||||
run_type.execute(&flatpak).args(&update_args).status_checked()?;
|
ctx.execute(&flatpak).args(&update_args).status_checked()?;
|
||||||
if cleanup {
|
if cleanup {
|
||||||
let mut cleanup_args = vec!["uninstall", "--system", "--unused"];
|
let mut cleanup_args = vec!["uninstall", "--system", "--unused"];
|
||||||
if yes {
|
if yes {
|
||||||
cleanup_args.push("-y");
|
cleanup_args.push("-y");
|
||||||
}
|
}
|
||||||
run_type.execute(flatpak).args(&cleanup_args).status_checked()?;
|
ctx.execute(flatpak).args(&cleanup_args).status_checked()?;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -936,7 +936,6 @@ pub fn run_flatpak(ctx: &ExecutionContext) -> Result<()> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn run_snap(ctx: &ExecutionContext) -> Result<()> {
|
pub fn run_snap(ctx: &ExecutionContext) -> Result<()> {
|
||||||
let sudo = require_option(ctx.sudo().as_ref(), get_require_sudo_string())?;
|
|
||||||
let snap = require("snap")?;
|
let snap = require("snap")?;
|
||||||
|
|
||||||
if !PathBuf::from("/var/snapd.socket").exists() && !PathBuf::from("/run/snapd.socket").exists() {
|
if !PathBuf::from("/var/snapd.socket").exists() && !PathBuf::from("/run/snapd.socket").exists() {
|
||||||
@@ -944,17 +943,18 @@ pub fn run_snap(ctx: &ExecutionContext) -> Result<()> {
|
|||||||
}
|
}
|
||||||
print_separator("snap");
|
print_separator("snap");
|
||||||
|
|
||||||
ctx.run_type().execute(sudo).arg(snap).arg("refresh").status_checked()
|
let sudo = ctx.require_sudo()?;
|
||||||
|
sudo.execute(ctx, &snap)?.arg("refresh").status_checked()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn run_pihole_update(ctx: &ExecutionContext) -> Result<()> {
|
pub fn run_pihole_update(ctx: &ExecutionContext) -> Result<()> {
|
||||||
let sudo = require_option(ctx.sudo().as_ref(), get_require_sudo_string())?;
|
|
||||||
let pihole = require("pihole")?;
|
let pihole = require("pihole")?;
|
||||||
Path::new("/opt/pihole/update.sh").require()?;
|
Path::new("/opt/pihole/update.sh").require()?;
|
||||||
|
|
||||||
print_separator("pihole");
|
print_separator("pihole");
|
||||||
|
|
||||||
ctx.run_type().execute(sudo).arg(pihole).arg("-up").status_checked()
|
let sudo = ctx.require_sudo()?;
|
||||||
|
sudo.execute(ctx, &pihole)?.arg("-up").status_checked()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn run_protonup_update(ctx: &ExecutionContext) -> Result<()> {
|
pub fn run_protonup_update(ctx: &ExecutionContext) -> Result<()> {
|
||||||
@@ -962,7 +962,7 @@ pub fn run_protonup_update(ctx: &ExecutionContext) -> Result<()> {
|
|||||||
|
|
||||||
print_separator("protonup");
|
print_separator("protonup");
|
||||||
|
|
||||||
let mut cmd = ctx.run_type().execute(protonup);
|
let mut cmd = ctx.execute(protonup);
|
||||||
if ctx.config().yes(Step::Protonup) {
|
if ctx.config().yes(Step::Protonup) {
|
||||||
cmd.arg("--yes");
|
cmd.arg("--yes");
|
||||||
}
|
}
|
||||||
@@ -977,7 +977,7 @@ pub fn run_distrobox_update(ctx: &ExecutionContext) -> Result<()> {
|
|||||||
print_separator("Distrobox");
|
print_separator("Distrobox");
|
||||||
match (
|
match (
|
||||||
match (
|
match (
|
||||||
ctx.run_type().execute(distrobox).arg("upgrade"),
|
ctx.execute(distrobox).arg("upgrade"),
|
||||||
ctx.config().distrobox_containers(),
|
ctx.config().distrobox_containers(),
|
||||||
) {
|
) {
|
||||||
(r, Some(c)) => {
|
(r, Some(c)) => {
|
||||||
@@ -997,44 +997,39 @@ pub fn run_distrobox_update(ctx: &ExecutionContext) -> Result<()> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn run_dkp_pacman_update(ctx: &ExecutionContext) -> Result<()> {
|
pub fn run_dkp_pacman_update(ctx: &ExecutionContext) -> Result<()> {
|
||||||
let sudo = require_option(ctx.sudo().as_ref(), get_require_sudo_string())?;
|
|
||||||
let dkp_pacman = require("dkp-pacman")?;
|
let dkp_pacman = require("dkp-pacman")?;
|
||||||
|
|
||||||
print_separator("Devkitpro pacman");
|
print_separator("Devkitpro pacman");
|
||||||
|
|
||||||
ctx.run_type()
|
let sudo = ctx.require_sudo()?;
|
||||||
.execute(sudo)
|
|
||||||
.arg(&dkp_pacman)
|
sudo.execute(ctx, &dkp_pacman)?.arg("-Syu").status_checked()?;
|
||||||
.arg("-Syu")
|
|
||||||
.status_checked()?;
|
|
||||||
|
|
||||||
if ctx.config().cleanup() {
|
if ctx.config().cleanup() {
|
||||||
ctx.run_type()
|
sudo.execute(ctx, &dkp_pacman)?.arg("-Scc").status_checked()?;
|
||||||
.execute(sudo)
|
|
||||||
.arg(&dkp_pacman)
|
|
||||||
.arg("-Scc")
|
|
||||||
.status_checked()?;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn run_config_update(ctx: &ExecutionContext) -> Result<()> {
|
pub fn run_config_update(ctx: &ExecutionContext) -> Result<()> {
|
||||||
let sudo = require_option(ctx.sudo().as_ref(), get_require_sudo_string())?;
|
|
||||||
if ctx.config().yes(Step::ConfigUpdate) {
|
if ctx.config().yes(Step::ConfigUpdate) {
|
||||||
return Err(SkipStep(t!("Skipped in --yes").to_string()).into());
|
return Err(SkipStep(t!("Skipped in --yes").to_string()).into());
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Ok(etc_update) = require("etc-update") {
|
if let Ok(etc_update) = require("etc-update") {
|
||||||
print_separator(t!("Configuration update"));
|
print_separator(t!("Configuration update"));
|
||||||
ctx.run_type().execute(sudo).arg(etc_update).status_checked()?;
|
let sudo = ctx.require_sudo()?;
|
||||||
|
sudo.execute(ctx, etc_update)?.status_checked()?;
|
||||||
} else if let Ok(pacdiff) = require("pacdiff") {
|
} else if let Ok(pacdiff) = require("pacdiff") {
|
||||||
if std::env::var("DIFFPROG").is_err() {
|
if std::env::var("DIFFPROG").is_err() {
|
||||||
require("vim")?;
|
require("vim")?;
|
||||||
}
|
}
|
||||||
|
|
||||||
print_separator(t!("Configuration update"));
|
print_separator(t!("Configuration update"));
|
||||||
ctx.execute_elevated(&pacdiff, false)?.status_checked()?;
|
let sudo = ctx.require_sudo()?;
|
||||||
|
sudo.execute_opts(ctx, &pacdiff, SudoExecuteOpts::new().preserve_env_list(&["DIFFPROG"]))?
|
||||||
|
.status_checked()?;
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
@@ -1045,7 +1040,7 @@ pub fn run_lure_update(ctx: &ExecutionContext) -> Result<()> {
|
|||||||
|
|
||||||
print_separator("LURE");
|
print_separator("LURE");
|
||||||
|
|
||||||
let mut exe = ctx.run_type().execute(lure);
|
let mut exe = ctx.execute(lure);
|
||||||
|
|
||||||
if ctx.config().yes(Step::Lure) {
|
if ctx.config().yes(Step::Lure) {
|
||||||
exe.args(["-i=false", "up"]);
|
exe.args(["-i=false", "up"]);
|
||||||
@@ -1057,9 +1052,9 @@ pub fn run_lure_update(ctx: &ExecutionContext) -> Result<()> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn run_waydroid(ctx: &ExecutionContext) -> Result<()> {
|
pub fn run_waydroid(ctx: &ExecutionContext) -> Result<()> {
|
||||||
let sudo = require_option(ctx.sudo().as_ref(), get_require_sudo_string())?;
|
|
||||||
let waydroid = require("waydroid")?;
|
let waydroid = require("waydroid")?;
|
||||||
let status = ctx.run_type().execute(&waydroid).arg("status").output_checked_utf8()?;
|
|
||||||
|
let status = ctx.execute(&waydroid).arg("status").output_checked_utf8()?;
|
||||||
// example output of `waydroid status`:
|
// example output of `waydroid status`:
|
||||||
//
|
//
|
||||||
// ```sh
|
// ```sh
|
||||||
@@ -1097,24 +1092,18 @@ pub fn run_waydroid(ctx: &ExecutionContext) -> Result<()> {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ctx.run_type()
|
|
||||||
.execute(sudo)
|
let sudo = ctx.require_sudo()?;
|
||||||
.arg(&waydroid)
|
sudo.execute(ctx, &waydroid)?.arg("upgrade").status_checked()
|
||||||
.arg("upgrade")
|
|
||||||
.status_checked()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn run_auto_cpufreq(ctx: &ExecutionContext) -> Result<()> {
|
pub fn run_auto_cpufreq(ctx: &ExecutionContext) -> Result<()> {
|
||||||
let sudo = require_option(ctx.sudo().as_ref(), get_require_sudo_string())?;
|
|
||||||
let auto_cpu_freq = require("auto-cpufreq")?;
|
let auto_cpu_freq = require("auto-cpufreq")?;
|
||||||
|
|
||||||
print_separator("auto-cpufreq");
|
print_separator("auto-cpufreq");
|
||||||
|
|
||||||
ctx.run_type()
|
let sudo = ctx.require_sudo()?;
|
||||||
.execute(sudo)
|
sudo.execute(ctx, &auto_cpu_freq)?.arg("--update").status_checked()
|
||||||
.arg(auto_cpu_freq)
|
|
||||||
.arg("--update")
|
|
||||||
.status_checked()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn run_cinnamon_spices_updater(ctx: &ExecutionContext) -> Result<()> {
|
pub fn run_cinnamon_spices_updater(ctx: &ExecutionContext) -> Result<()> {
|
||||||
@@ -1122,10 +1111,7 @@ pub fn run_cinnamon_spices_updater(ctx: &ExecutionContext) -> Result<()> {
|
|||||||
|
|
||||||
print_separator("Cinnamon spices");
|
print_separator("Cinnamon spices");
|
||||||
|
|
||||||
ctx.run_type()
|
ctx.execute(cinnamon_spice_updater).arg("--update-all").status_checked()
|
||||||
.execute(cinnamon_spice_updater)
|
|
||||||
.arg("--update-all")
|
|
||||||
.status_checked()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
@@ -1316,4 +1302,9 @@ mod tests {
|
|||||||
fn test_bazzite() {
|
fn test_bazzite() {
|
||||||
test_template(include_str!("os_release/bazzite"), Distribution::FedoraImmutable);
|
test_template(include_str!("os_release/bazzite"), Distribution::FedoraImmutable);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_cachyos() {
|
||||||
|
test_template(include_str!("os_release/cachyos"), Distribution::Arch);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
use crate::command::CommandExt;
|
use crate::command::CommandExt;
|
||||||
use crate::execution_context::ExecutionContext;
|
use crate::execution_context::ExecutionContext;
|
||||||
|
use crate::step::Step;
|
||||||
use crate::terminal::{print_separator, prompt_yesno};
|
use crate::terminal::{print_separator, prompt_yesno};
|
||||||
use crate::utils::{get_require_sudo_string, require_option};
|
use crate::utils::require;
|
||||||
use crate::{utils::require, Step};
|
|
||||||
use color_eyre::eyre::Result;
|
use color_eyre::eyre::Result;
|
||||||
use rust_i18n::t;
|
use rust_i18n::t;
|
||||||
use std::collections::HashSet;
|
use std::collections::HashSet;
|
||||||
@@ -11,23 +11,18 @@ use std::process::Command;
|
|||||||
use tracing::debug;
|
use tracing::debug;
|
||||||
|
|
||||||
pub fn run_macports(ctx: &ExecutionContext) -> Result<()> {
|
pub fn run_macports(ctx: &ExecutionContext) -> Result<()> {
|
||||||
require("port")?;
|
let port = require("port")?;
|
||||||
let sudo = require_option(ctx.sudo().as_ref(), get_require_sudo_string())?;
|
|
||||||
|
|
||||||
print_separator("MacPorts");
|
print_separator("MacPorts");
|
||||||
ctx.run_type()
|
|
||||||
.execute(sudo)
|
let sudo = ctx.require_sudo()?;
|
||||||
.args(["port", "selfupdate"])
|
|
||||||
.status_checked()?;
|
sudo.execute(ctx, &port)?.arg("selfupdate").status_checked()?;
|
||||||
ctx.run_type()
|
sudo.execute(ctx, &port)?
|
||||||
.execute(sudo)
|
.args(["-u", "upgrade", "outdated"])
|
||||||
.args(["port", "-u", "upgrade", "outdated"])
|
|
||||||
.status_checked()?;
|
.status_checked()?;
|
||||||
if ctx.config().cleanup() {
|
if ctx.config().cleanup() {
|
||||||
ctx.run_type()
|
sudo.execute(ctx, &port)?.args(["-N", "reclaim"]).status_checked()?;
|
||||||
.execute(sudo)
|
|
||||||
.args(["port", "-N", "reclaim"])
|
|
||||||
.status_checked()?;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
@@ -37,7 +32,7 @@ pub fn run_mas(ctx: &ExecutionContext) -> Result<()> {
|
|||||||
let mas = require("mas")?;
|
let mas = require("mas")?;
|
||||||
print_separator(t!("macOS App Store"));
|
print_separator(t!("macOS App Store"));
|
||||||
|
|
||||||
ctx.run_type().execute(mas).arg("upgrade").status_checked()
|
ctx.execute(mas).arg("upgrade").status_checked()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn upgrade_macos(ctx: &ExecutionContext) -> Result<()> {
|
pub fn upgrade_macos(ctx: &ExecutionContext) -> Result<()> {
|
||||||
@@ -58,7 +53,7 @@ pub fn upgrade_macos(ctx: &ExecutionContext) -> Result<()> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut command = ctx.run_type().execute("softwareupdate");
|
let mut command = ctx.execute("softwareupdate");
|
||||||
command.args(["--install", "--all"]);
|
command.args(["--install", "--all"]);
|
||||||
|
|
||||||
if should_ask {
|
if should_ask {
|
||||||
@@ -87,7 +82,7 @@ pub fn run_sparkle(ctx: &ExecutionContext) -> Result<()> {
|
|||||||
.arg(application.path())
|
.arg(application.path())
|
||||||
.output_checked_utf8();
|
.output_checked_utf8();
|
||||||
if probe.is_ok() {
|
if probe.is_ok() {
|
||||||
let mut command = ctx.run_type().execute(&sparkle);
|
let mut command = ctx.execute(&sparkle);
|
||||||
command.args(["bundle", "--check-immediately", "--application"]);
|
command.args(["bundle", "--check-immediately", "--application"]);
|
||||||
command.arg(application.path());
|
command.arg(application.path());
|
||||||
command.status_checked()?;
|
command.status_checked()?;
|
||||||
@@ -102,12 +97,7 @@ pub fn update_xcodes(ctx: &ExecutionContext) -> Result<()> {
|
|||||||
|
|
||||||
let should_ask = !(ctx.config().yes(Step::Xcodes) || ctx.config().dry_run());
|
let should_ask = !(ctx.config().yes(Step::Xcodes) || ctx.config().dry_run());
|
||||||
|
|
||||||
let releases = ctx
|
let releases = ctx.execute(&xcodes).args(["update"]).output_checked_utf8()?.stdout;
|
||||||
.run_type()
|
|
||||||
.execute(&xcodes)
|
|
||||||
.args(["update"])
|
|
||||||
.output_checked_utf8()?
|
|
||||||
.stdout;
|
|
||||||
|
|
||||||
let releases_installed: Vec<String> = releases
|
let releases_installed: Vec<String> = releases
|
||||||
.lines()
|
.lines()
|
||||||
@@ -164,12 +154,7 @@ pub fn update_xcodes(ctx: &ExecutionContext) -> Result<()> {
|
|||||||
process_xcodes_releases(releases_regular, should_ask, ctx)?;
|
process_xcodes_releases(releases_regular, should_ask, ctx)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
let releases_new = ctx
|
let releases_new = ctx.execute(&xcodes).args(["list"]).output_checked_utf8()?.stdout;
|
||||||
.run_type()
|
|
||||||
.execute(&xcodes)
|
|
||||||
.args(["list"])
|
|
||||||
.output_checked_utf8()?
|
|
||||||
.stdout;
|
|
||||||
|
|
||||||
let releases_gm_new_installed: HashSet<_> = releases_new
|
let releases_gm_new_installed: HashSet<_> = releases_new
|
||||||
.lines()
|
.lines()
|
||||||
@@ -199,7 +184,6 @@ pub fn update_xcodes(ctx: &ExecutionContext) -> Result<()> {
|
|||||||
prompt_yesno(t!("Would you like to move the former Xcode release to the trash?").as_ref())?;
|
prompt_yesno(t!("Would you like to move the former Xcode release to the trash?").as_ref())?;
|
||||||
if answer_uninstall {
|
if answer_uninstall {
|
||||||
let _ = ctx
|
let _ = ctx
|
||||||
.run_type()
|
|
||||||
.execute(&xcodes)
|
.execute(&xcodes)
|
||||||
.args([
|
.args([
|
||||||
"uninstall",
|
"uninstall",
|
||||||
@@ -226,7 +210,6 @@ pub fn process_xcodes_releases(releases_filtered: Vec<String>, should_ask: bool,
|
|||||||
let answer_install = prompt_yesno(t!("Would you like to install it?").as_ref())?;
|
let answer_install = prompt_yesno(t!("Would you like to install it?").as_ref())?;
|
||||||
if answer_install {
|
if answer_install {
|
||||||
let _ = ctx
|
let _ = ctx
|
||||||
.run_type()
|
|
||||||
.execute(xcodes)
|
.execute(xcodes)
|
||||||
.args(["install", &releases_filtered.last().cloned().unwrap_or_default()])
|
.args(["install", &releases_filtered.last().cloned().unwrap_or_default()])
|
||||||
.status_checked();
|
.status_checked();
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
use crate::command::CommandExt;
|
use crate::command::CommandExt;
|
||||||
use crate::execution_context::ExecutionContext;
|
use crate::execution_context::ExecutionContext;
|
||||||
use crate::terminal::print_separator;
|
use crate::terminal::print_separator;
|
||||||
use crate::utils::{get_require_sudo_string, require_option};
|
|
||||||
use color_eyre::eyre::Result;
|
use color_eyre::eyre::Result;
|
||||||
use rust_i18n::t;
|
use rust_i18n::t;
|
||||||
use std::fs;
|
use std::fs;
|
||||||
@@ -18,9 +17,10 @@ fn is_openbsd_current(ctx: &ExecutionContext) -> Result<bool> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn upgrade_openbsd(ctx: &ExecutionContext) -> Result<()> {
|
pub fn upgrade_openbsd(ctx: &ExecutionContext) -> Result<()> {
|
||||||
let sudo = require_option(ctx.sudo().as_ref(), get_require_sudo_string())?;
|
|
||||||
print_separator(t!("OpenBSD Update"));
|
print_separator(t!("OpenBSD Update"));
|
||||||
|
|
||||||
|
let sudo = ctx.require_sudo()?;
|
||||||
|
|
||||||
let is_current = is_openbsd_current(ctx)?;
|
let is_current = is_openbsd_current(ctx)?;
|
||||||
|
|
||||||
if ctx.config().dry_run() {
|
if ctx.config().dry_run() {
|
||||||
@@ -28,19 +28,18 @@ pub fn upgrade_openbsd(ctx: &ExecutionContext) -> Result<()> {
|
|||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
|
|
||||||
let args = if is_current {
|
if is_current {
|
||||||
vec!["/usr/sbin/sysupgrade", "-sn"]
|
sudo.execute(ctx, "/usr/sbin/sysupgrade")?.arg("-sn").status_checked()
|
||||||
} else {
|
} else {
|
||||||
vec!["/usr/sbin/syspatch"]
|
sudo.execute(ctx, "/usr/sbin/syspatch")?.status_checked()
|
||||||
};
|
}
|
||||||
|
|
||||||
ctx.run_type().execute(sudo).args(&args).status_checked()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn upgrade_packages(ctx: &ExecutionContext) -> Result<()> {
|
pub fn upgrade_packages(ctx: &ExecutionContext) -> Result<()> {
|
||||||
let sudo = require_option(ctx.sudo().as_ref(), get_require_sudo_string())?;
|
|
||||||
print_separator(t!("OpenBSD Packages"));
|
print_separator(t!("OpenBSD Packages"));
|
||||||
|
|
||||||
|
let sudo = ctx.require_sudo()?;
|
||||||
|
|
||||||
let is_current = is_openbsd_current(ctx)?;
|
let is_current = is_openbsd_current(ctx)?;
|
||||||
|
|
||||||
if ctx.config().dry_run() {
|
if ctx.config().dry_run() {
|
||||||
@@ -49,18 +48,13 @@ pub fn upgrade_packages(ctx: &ExecutionContext) -> Result<()> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if ctx.config().cleanup() {
|
if ctx.config().cleanup() {
|
||||||
ctx.run_type()
|
sudo.execute(ctx, "/usr/sbin/pkg_delete")?.arg("-ac").status_checked()?;
|
||||||
.execute(sudo)
|
|
||||||
.args(["/usr/sbin/pkg_delete", "-ac"])
|
|
||||||
.status_checked()?;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut args = vec!["/usr/sbin/pkg_add", "-u"];
|
let mut command = sudo.execute(ctx, "/usr/sbin/pkg_add")?;
|
||||||
|
command.arg("-u");
|
||||||
if is_current {
|
if is_current {
|
||||||
args.push("-Dsnap");
|
command.arg("-Dsnap");
|
||||||
}
|
}
|
||||||
|
command.status_checked()
|
||||||
ctx.run_type().execute(sudo).args(&args).status_checked()?;
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,4 +6,4 @@ VERSION_ID="2"
|
|||||||
PRETTY_NAME="Amazon Linux 2"
|
PRETTY_NAME="Amazon Linux 2"
|
||||||
ANSI_COLOR="0;33"
|
ANSI_COLOR="0;33"
|
||||||
CPE_NAME="cpe:2.3:o:amazon:amazon_linux:2"
|
CPE_NAME="cpe:2.3:o:amazon:amazon_linux:2"
|
||||||
HOME_URL="https://amazonlinux.com/"
|
HOME_URL="https://amazonlinux.com/"
|
||||||
|
|||||||
@@ -8,4 +8,4 @@ HOME_URL="https://www.archlinux32.org/"
|
|||||||
DOCUMENTATION_URL="https://wiki.archlinux.org/"
|
DOCUMENTATION_URL="https://wiki.archlinux.org/"
|
||||||
SUPPORT_URL="https://bbs.archlinux32.org/"
|
SUPPORT_URL="https://bbs.archlinux32.org/"
|
||||||
BUG_REPORT_URL="https://bugs.archlinux32.org/"
|
BUG_REPORT_URL="https://bugs.archlinux32.org/"
|
||||||
LOGO=archlinux
|
LOGO=archlinux
|
||||||
|
|||||||
@@ -22,4 +22,4 @@ OSTREE_VERSION='41.20250208.0'
|
|||||||
BUILD_ID="Stable (F41.20250208)"
|
BUILD_ID="Stable (F41.20250208)"
|
||||||
BOOTLOADER_NAME="Bazzite Stable (F41.20250208)"
|
BOOTLOADER_NAME="Bazzite Stable (F41.20250208)"
|
||||||
BUILD_ID="Stable (F41.20250208)"
|
BUILD_ID="Stable (F41.20250208)"
|
||||||
BOOTLOADER_NAME="Bazzite Stable (F41.20250208)"
|
BOOTLOADER_NAME="Bazzite Stable (F41.20250208)"
|
||||||
|
|||||||
11
src/steps/os/os_release/cachyos
Normal file
11
src/steps/os/os_release/cachyos
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
NAME="CachyOS Linux"
|
||||||
|
PRETTY_NAME="CachyOS"
|
||||||
|
ID=cachyos
|
||||||
|
BUILD_ID=rolling
|
||||||
|
ANSI_COLOR="38;2;23;147;209"
|
||||||
|
HOME_URL="https://cachyos.org/"
|
||||||
|
DOCUMENTATION_URL="https://wiki.cachyos.org/"
|
||||||
|
SUPPORT_URL="https://discuss.cachyos.org/"
|
||||||
|
BUG_REPORT_URL="https://github.com/cachyos"
|
||||||
|
PRIVACY_POLICY_URL="https://terms.archlinux.org/docs/privacy-policy/"
|
||||||
|
LOGO=cachyos
|
||||||
@@ -13,4 +13,3 @@ CENTOS_MANTISBT_PROJECT="CentOS-7"
|
|||||||
CENTOS_MANTISBT_PROJECT_VERSION="7"
|
CENTOS_MANTISBT_PROJECT_VERSION="7"
|
||||||
REDHAT_SUPPORT_PRODUCT="centos"
|
REDHAT_SUPPORT_PRODUCT="centos"
|
||||||
REDHAT_SUPPORT_PRODUCT_VERSION="7"
|
REDHAT_SUPPORT_PRODUCT_VERSION="7"
|
||||||
|
|
||||||
|
|||||||
@@ -20,4 +20,4 @@ REDHAT_SUPPORT_PRODUCT_VERSION=40
|
|||||||
SUPPORT_END=2025-05-13
|
SUPPORT_END=2025-05-13
|
||||||
VARIANT="Sway Atomic"
|
VARIANT="Sway Atomic"
|
||||||
VARIANT_ID=sway-atomic
|
VARIANT_ID=sway-atomic
|
||||||
OSTREE_VERSION='40.20240426.0'
|
OSTREE_VERSION='40.20240426.0'
|
||||||
|
|||||||
@@ -7,4 +7,4 @@ HOME_URL="https://www.garudalinux.in/"
|
|||||||
DOCUMENTATION_URL="https://wiki.archlinux.org/"
|
DOCUMENTATION_URL="https://wiki.archlinux.org/"
|
||||||
SUPPORT_URL="https://forum.garudalinux.in/"
|
SUPPORT_URL="https://forum.garudalinux.in/"
|
||||||
BUG_REPORT_URL="https://gitlab.com/groups/garuda-linux/"
|
BUG_REPORT_URL="https://gitlab.com/groups/garuda-linux/"
|
||||||
LOGO=garudalinux
|
LOGO=garudalinux
|
||||||
|
|||||||
@@ -4,4 +4,3 @@ PRETTY_NAME="Manjaro ARM"
|
|||||||
ANSI_COLOR="1;32"
|
ANSI_COLOR="1;32"
|
||||||
HOME_URL="https://www.manjaro.org/"
|
HOME_URL="https://www.manjaro.org/"
|
||||||
SUPPORT_URL="https://forum.manjaro.org/c/manjaro-arm/"
|
SUPPORT_URL="https://forum.manjaro.org/c/manjaro-arm/"
|
||||||
|
|
||||||
|
|||||||
@@ -1,36 +1,38 @@
|
|||||||
|
use color_eyre::eyre::eyre;
|
||||||
|
use color_eyre::eyre::Context;
|
||||||
|
use color_eyre::eyre::Result;
|
||||||
|
use etcetera::BaseStrategy;
|
||||||
|
use home;
|
||||||
|
use ini::Ini;
|
||||||
|
#[cfg(target_os = "linux")]
|
||||||
|
use nix::unistd::Uid;
|
||||||
|
use regex::Regex;
|
||||||
|
use rust_i18n::t;
|
||||||
|
use semver::Version;
|
||||||
use std::ffi::OsStr;
|
use std::ffi::OsStr;
|
||||||
use std::fs;
|
use std::fs;
|
||||||
use std::os::unix::fs::MetadataExt;
|
use std::os::unix::fs::MetadataExt;
|
||||||
use std::path::Component;
|
use std::path::Component;
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
use std::process::Command;
|
use std::process::Command;
|
||||||
|
use std::sync::LazyLock;
|
||||||
use std::{env::var, path::Path};
|
use std::{env::var, path::Path};
|
||||||
|
use tracing::{debug, warn};
|
||||||
|
|
||||||
use crate::command::CommandExt;
|
use crate::command::CommandExt;
|
||||||
use crate::{Step, HOME_DIR};
|
use crate::sudo::SudoExecuteOpts;
|
||||||
use color_eyre::eyre::eyre;
|
use crate::XDG_DIRS;
|
||||||
use color_eyre::eyre::Context;
|
use crate::{output_changed_message, HOME_DIR};
|
||||||
use color_eyre::eyre::Result;
|
|
||||||
use home;
|
|
||||||
use ini::Ini;
|
|
||||||
use lazy_static::lazy_static;
|
|
||||||
#[cfg(target_os = "linux")]
|
|
||||||
use nix::unistd::Uid;
|
|
||||||
use regex::Regex;
|
|
||||||
use rust_i18n::t;
|
|
||||||
use semver::Version;
|
|
||||||
use tracing::debug;
|
|
||||||
|
|
||||||
#[cfg(target_os = "linux")]
|
#[cfg(target_os = "linux")]
|
||||||
use super::linux::Distribution;
|
use super::linux::Distribution;
|
||||||
use crate::error::SkipStep;
|
use crate::error::{SkipStep, StepFailed};
|
||||||
use crate::execution_context::ExecutionContext;
|
use crate::execution_context::ExecutionContext;
|
||||||
#[cfg(any(target_os = "linux", target_os = "macos"))]
|
#[cfg(any(target_os = "linux", target_os = "macos"))]
|
||||||
use crate::executor::Executor;
|
use crate::executor::Executor;
|
||||||
#[cfg(any(target_os = "linux", target_os = "macos"))]
|
use crate::step::Step;
|
||||||
use crate::executor::RunType;
|
|
||||||
use crate::terminal::print_separator;
|
use crate::terminal::print_separator;
|
||||||
use crate::utils::{get_require_sudo_string, require, require_option, PathExt};
|
use crate::utils::{require, PathExt};
|
||||||
|
|
||||||
#[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";
|
||||||
@@ -75,19 +77,41 @@ impl BrewVariant {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn execute(self, run_type: RunType) -> Executor {
|
/// Execute an "internal" brew command, i.e. one that should always be run
|
||||||
|
/// even when dry-running. Basically just a wrapper around [`Command::new`]
|
||||||
|
/// that uses `arch` to run using the correct architecture if needed.
|
||||||
|
#[cfg(target_os = "macos")]
|
||||||
|
fn execute_internal(self) -> Command {
|
||||||
match self {
|
match self {
|
||||||
BrewVariant::MacIntel if cfg!(target_arch = "aarch64") => {
|
BrewVariant::MacIntel if cfg!(target_arch = "aarch64") => {
|
||||||
let mut command = run_type.execute("arch");
|
let mut command = Command::new("arch");
|
||||||
command.arg("-x86_64").arg(self.binary_name());
|
command.arg("-x86_64").arg(self.binary_name());
|
||||||
command
|
command
|
||||||
}
|
}
|
||||||
BrewVariant::MacArm if cfg!(target_arch = "x86_64") => {
|
BrewVariant::MacArm if cfg!(target_arch = "x86_64") => {
|
||||||
let mut command = run_type.execute("arch");
|
let mut command = Command::new("arch");
|
||||||
command.arg("-arm64e").arg(self.binary_name());
|
command.arg("-arm64e").arg(self.binary_name());
|
||||||
command
|
command
|
||||||
}
|
}
|
||||||
_ => run_type.execute(self.binary_name()),
|
_ => Command::new(self.binary_name()),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Execute a brew command. Uses `arch` to run using the correct
|
||||||
|
/// architecture on macOS if needed.
|
||||||
|
fn execute(self, ctx: &ExecutionContext) -> Executor {
|
||||||
|
match self {
|
||||||
|
BrewVariant::MacIntel if cfg!(target_arch = "aarch64") => {
|
||||||
|
let mut command = ctx.execute("arch");
|
||||||
|
command.arg("-x86_64").arg(self.binary_name());
|
||||||
|
command
|
||||||
|
}
|
||||||
|
BrewVariant::MacArm if cfg!(target_arch = "x86_64") => {
|
||||||
|
let mut command = ctx.execute("arch");
|
||||||
|
command.arg("-arm64e").arg(self.binary_name());
|
||||||
|
command
|
||||||
|
}
|
||||||
|
_ => ctx.execute(self.binary_name()),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -121,7 +145,6 @@ pub fn run_fisher(ctx: &ExecutionContext) -> Result<()> {
|
|||||||
print_separator("Fisher");
|
print_separator("Fisher");
|
||||||
|
|
||||||
let version_str = ctx
|
let version_str = ctx
|
||||||
.run_type()
|
|
||||||
.execute(&fish)
|
.execute(&fish)
|
||||||
.args(["-c", "fisher --version"])
|
.args(["-c", "fisher --version"])
|
||||||
.output_checked_utf8()?
|
.output_checked_utf8()?
|
||||||
@@ -130,13 +153,10 @@ pub fn run_fisher(ctx: &ExecutionContext) -> Result<()> {
|
|||||||
|
|
||||||
if version_str.starts_with("fisher version 3.") {
|
if version_str.starts_with("fisher version 3.") {
|
||||||
// v3 - see https://github.com/topgrade-rs/topgrade/pull/37#issuecomment-1283844506
|
// v3 - see https://github.com/topgrade-rs/topgrade/pull/37#issuecomment-1283844506
|
||||||
ctx.run_type().execute(&fish).args(["-c", "fisher"]).status_checked()
|
ctx.execute(&fish).args(["-c", "fisher"]).status_checked()
|
||||||
} else {
|
} else {
|
||||||
// v4
|
// v4
|
||||||
ctx.run_type()
|
ctx.execute(&fish).args(["-c", "fisher update"]).status_checked()
|
||||||
.execute(&fish)
|
|
||||||
.args(["-c", "fisher update"])
|
|
||||||
.status_checked()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -145,8 +165,7 @@ pub fn run_bashit(ctx: &ExecutionContext) -> Result<()> {
|
|||||||
|
|
||||||
print_separator("Bash-it");
|
print_separator("Bash-it");
|
||||||
|
|
||||||
ctx.run_type()
|
ctx.execute("bash")
|
||||||
.execute("bash")
|
|
||||||
.args(["-lic", &format!("bash-it update {}", ctx.config().bashit_branch())])
|
.args(["-lic", &format!("bash-it update {}", ctx.config().bashit_branch())])
|
||||||
.status_checked()
|
.status_checked()
|
||||||
}
|
}
|
||||||
@@ -169,7 +188,7 @@ pub fn run_oh_my_bash(ctx: &ExecutionContext) -> Result<()> {
|
|||||||
let mut update_script = oh_my_bash;
|
let mut update_script = oh_my_bash;
|
||||||
update_script.push_str("/tools/upgrade.sh");
|
update_script.push_str("/tools/upgrade.sh");
|
||||||
|
|
||||||
ctx.run_type().execute("bash").arg(update_script).status_checked()
|
ctx.execute("bash").arg(update_script).status_checked()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn run_oh_my_fish(ctx: &ExecutionContext) -> Result<()> {
|
pub fn run_oh_my_fish(ctx: &ExecutionContext) -> Result<()> {
|
||||||
@@ -178,24 +197,25 @@ pub fn run_oh_my_fish(ctx: &ExecutionContext) -> Result<()> {
|
|||||||
|
|
||||||
print_separator("oh-my-fish");
|
print_separator("oh-my-fish");
|
||||||
|
|
||||||
ctx.run_type().execute(fish).args(["-c", "omf update"]).status_checked()
|
ctx.execute(fish).args(["-c", "omf update"]).status_checked()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn run_pkgin(ctx: &ExecutionContext) -> Result<()> {
|
pub fn run_pkgin(ctx: &ExecutionContext) -> Result<()> {
|
||||||
let pkgin = require("pkgin")?;
|
let pkgin = require("pkgin")?;
|
||||||
let sudo = require_option(ctx.sudo().as_ref(), get_require_sudo_string())?;
|
|
||||||
|
|
||||||
print_separator("Pkgin");
|
print_separator("Pkgin");
|
||||||
|
|
||||||
let mut command = ctx.run_type().execute(sudo);
|
let sudo = ctx.require_sudo()?;
|
||||||
command.arg(&pkgin).arg("update");
|
|
||||||
|
let mut command = sudo.execute(ctx, &pkgin)?;
|
||||||
|
command.arg("update");
|
||||||
if ctx.config().yes(Step::Pkgin) {
|
if ctx.config().yes(Step::Pkgin) {
|
||||||
command.arg("-y");
|
command.arg("-y");
|
||||||
}
|
}
|
||||||
command.status_checked()?;
|
command.status_checked()?;
|
||||||
|
|
||||||
let mut command = ctx.run_type().execute(sudo);
|
let mut command = sudo.execute(ctx, &pkgin)?;
|
||||||
command.arg(&pkgin).arg("upgrade");
|
command.arg("upgrade");
|
||||||
if ctx.config().yes(Step::Pkgin) {
|
if ctx.config().yes(Step::Pkgin) {
|
||||||
command.arg("-y");
|
command.arg("-y");
|
||||||
}
|
}
|
||||||
@@ -210,10 +230,7 @@ pub fn run_fish_plug(ctx: &ExecutionContext) -> Result<()> {
|
|||||||
|
|
||||||
print_separator("fish-plug");
|
print_separator("fish-plug");
|
||||||
|
|
||||||
ctx.run_type()
|
ctx.execute(fish).args(["-c", "plug update"]).status_checked()
|
||||||
.execute(fish)
|
|
||||||
.args(["-c", "plug update"])
|
|
||||||
.status_checked()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Upgrades `fundle` and `fundle` plugins.
|
/// Upgrades `fundle` and `fundle` plugins.
|
||||||
@@ -227,8 +244,7 @@ pub fn run_fundle(ctx: &ExecutionContext) -> Result<()> {
|
|||||||
|
|
||||||
print_separator("fundle");
|
print_separator("fundle");
|
||||||
|
|
||||||
ctx.run_type()
|
ctx.execute(fish)
|
||||||
.execute(fish)
|
|
||||||
.args(["-c", "fundle self-update && fundle update"])
|
.args(["-c", "fundle self-update && fundle update"])
|
||||||
.status_checked()
|
.status_checked()
|
||||||
}
|
}
|
||||||
@@ -236,9 +252,9 @@ pub fn run_fundle(ctx: &ExecutionContext) -> Result<()> {
|
|||||||
#[cfg(not(any(target_os = "android", target_os = "macos")))]
|
#[cfg(not(any(target_os = "android", target_os = "macos")))]
|
||||||
pub fn upgrade_gnome_extensions(ctx: &ExecutionContext) -> Result<()> {
|
pub fn upgrade_gnome_extensions(ctx: &ExecutionContext) -> Result<()> {
|
||||||
let gdbus = require("gdbus")?;
|
let gdbus = require("gdbus")?;
|
||||||
require_option(
|
crate::utils::require_option(
|
||||||
var("XDG_CURRENT_DESKTOP").ok().filter(|p| p.contains("GNOME")),
|
var("XDG_CURRENT_DESKTOP").ok().filter(|p| p.contains("GNOME")),
|
||||||
t!("Desktop doest not appear to be gnome").to_string(),
|
t!("Desktop does not appear to be GNOME").to_string(),
|
||||||
)?;
|
)?;
|
||||||
let output = Command::new("gdbus")
|
let output = Command::new("gdbus")
|
||||||
.args([
|
.args([
|
||||||
@@ -253,15 +269,14 @@ pub fn upgrade_gnome_extensions(ctx: &ExecutionContext) -> Result<()> {
|
|||||||
])
|
])
|
||||||
.output_checked_utf8()?;
|
.output_checked_utf8()?;
|
||||||
|
|
||||||
debug!("Checking for gnome extensions: {}", output);
|
debug!("Checking for GNOME extensions: {}", output);
|
||||||
if !output.stdout.contains("org.gnome.Shell.Extensions") {
|
if !output.stdout.contains("org.gnome.Shell.Extensions") {
|
||||||
return Err(SkipStep(t!("Gnome shell extensions are unregistered in DBus").to_string()).into());
|
return Err(SkipStep(t!("GNOME shell extensions are unregistered in DBus").to_string()).into());
|
||||||
}
|
}
|
||||||
|
|
||||||
print_separator(t!("Gnome Shell extensions"));
|
print_separator(t!("GNOME Shell extensions"));
|
||||||
|
|
||||||
ctx.run_type()
|
ctx.execute(gdbus)
|
||||||
.execute(gdbus)
|
|
||||||
.args([
|
.args([
|
||||||
"call",
|
"call",
|
||||||
"--session",
|
"--session",
|
||||||
@@ -317,26 +332,19 @@ pub fn run_brew_formula(ctx: &ExecutionContext, variant: BrewVariant) -> Result<
|
|||||||
let sudo_as_user = t!("sudo as user '{user}'", user = user.name);
|
let sudo_as_user = t!("sudo as user '{user}'", user = user.name);
|
||||||
print_separator(format!("{} ({})", variant.step_title(), sudo_as_user));
|
print_separator(format!("{} ({})", variant.step_title(), sudo_as_user));
|
||||||
|
|
||||||
let sudo = crate::utils::require_option(ctx.sudo().as_ref(), crate::utils::get_require_sudo_string())?;
|
let sudo = ctx.require_sudo()?;
|
||||||
ctx.run_type()
|
sudo.execute_opts(ctx, &binary_name, SudoExecuteOpts::new().set_home().user(&user.name))?
|
||||||
.execute(sudo)
|
|
||||||
.current_dir("/tmp") // brew needs a writable current directory
|
.current_dir("/tmp") // brew needs a writable current directory
|
||||||
.args([
|
.arg("update")
|
||||||
"--set-home",
|
|
||||||
&format!("--user={}", user.name),
|
|
||||||
&format!("{}", binary_name.to_string_lossy()),
|
|
||||||
"update",
|
|
||||||
])
|
|
||||||
.status_checked()?;
|
.status_checked()?;
|
||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
print_separator(variant.step_title());
|
print_separator(variant.step_title());
|
||||||
let run_type = ctx.run_type();
|
|
||||||
|
|
||||||
variant.execute(run_type).arg("update").status_checked()?;
|
variant.execute(ctx).arg("update").status_checked()?;
|
||||||
|
|
||||||
let mut command = variant.execute(run_type);
|
let mut command = variant.execute(ctx);
|
||||||
command.args(["upgrade", "--formula"]);
|
command.args(["upgrade", "--formula"]);
|
||||||
|
|
||||||
if ctx.config().brew_fetch_head() {
|
if ctx.config().brew_fetch_head() {
|
||||||
@@ -346,11 +354,11 @@ pub fn run_brew_formula(ctx: &ExecutionContext, variant: BrewVariant) -> Result<
|
|||||||
command.status_checked()?;
|
command.status_checked()?;
|
||||||
|
|
||||||
if ctx.config().cleanup() {
|
if ctx.config().cleanup() {
|
||||||
variant.execute(run_type).arg("cleanup").status_checked()?;
|
variant.execute(ctx).arg("cleanup").status_checked()?;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ctx.config().brew_autoremove() {
|
if ctx.config().brew_autoremove() {
|
||||||
variant.execute(run_type).arg("autoremove").status_checked()?;
|
variant.execute(ctx).arg("autoremove").status_checked()?;
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
@@ -363,10 +371,9 @@ pub fn run_brew_cask(ctx: &ExecutionContext, variant: BrewVariant) -> Result<()>
|
|||||||
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());
|
||||||
}
|
}
|
||||||
print_separator(format!("{} - Cask", variant.step_title()));
|
print_separator(format!("{} - Cask", variant.step_title()));
|
||||||
let run_type = ctx.run_type();
|
|
||||||
|
|
||||||
let cask_upgrade_exists = variant
|
let cask_upgrade_exists = variant
|
||||||
.execute(RunType::Wet)
|
.execute_internal()
|
||||||
.args(["--repository", "buo/cask-upgrade"])
|
.args(["--repository", "buo/cask-upgrade"])
|
||||||
.output_checked_utf8()
|
.output_checked_utf8()
|
||||||
.map(|p| Path::new(p.stdout.trim()).exists())?;
|
.map(|p| Path::new(p.stdout.trim()).exists())?;
|
||||||
@@ -391,10 +398,10 @@ pub fn run_brew_cask(ctx: &ExecutionContext, variant: BrewVariant) -> Result<()>
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
variant.execute(run_type).args(&brew_args).status_checked()?;
|
variant.execute(ctx).args(&brew_args).status_checked()?;
|
||||||
|
|
||||||
if ctx.config().cleanup() {
|
if ctx.config().cleanup() {
|
||||||
variant.execute(run_type).arg("cleanup").status_checked()?;
|
variant.execute(ctx).arg("cleanup").status_checked()?;
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
@@ -403,8 +410,6 @@ pub fn run_brew_cask(ctx: &ExecutionContext, variant: BrewVariant) -> Result<()>
|
|||||||
pub fn run_guix(ctx: &ExecutionContext) -> Result<()> {
|
pub fn run_guix(ctx: &ExecutionContext) -> Result<()> {
|
||||||
let guix = require("guix")?;
|
let guix = require("guix")?;
|
||||||
|
|
||||||
let run_type = ctx.run_type();
|
|
||||||
|
|
||||||
let output = Command::new(&guix).arg("pull").output_checked_utf8();
|
let output = Command::new(&guix).arg("pull").output_checked_utf8();
|
||||||
debug!("guix pull output: {:?}", output);
|
debug!("guix pull output: {:?}", output);
|
||||||
let should_upgrade = output.is_ok();
|
let should_upgrade = output.is_ok();
|
||||||
@@ -413,7 +418,7 @@ pub fn run_guix(ctx: &ExecutionContext) -> Result<()> {
|
|||||||
print_separator("Guix");
|
print_separator("Guix");
|
||||||
|
|
||||||
if should_upgrade {
|
if should_upgrade {
|
||||||
return run_type.execute(&guix).args(["package", "-u"]).status_checked();
|
return ctx.execute(&guix).args(["package", "-u"]).status_checked();
|
||||||
}
|
}
|
||||||
Err(SkipStep(t!("Guix Pull Failed, Skipping").to_string()).into())
|
Err(SkipStep(t!("Guix Pull Failed, Skipping").to_string()).into())
|
||||||
}
|
}
|
||||||
@@ -424,7 +429,11 @@ pub fn run_nix(ctx: &ExecutionContext) -> Result<()> {
|
|||||||
let nix_env = require("nix-env")?;
|
let nix_env = require("nix-env")?;
|
||||||
// TODO: Is None possible here?
|
// TODO: Is None possible here?
|
||||||
let profile_path = match home::home_dir() {
|
let profile_path = match home::home_dir() {
|
||||||
Some(home) => Path::new(&home).join(".nix-profile"),
|
Some(home) => XDG_DIRS
|
||||||
|
.state_dir()
|
||||||
|
.map(|d| d.join("nix/profile"))
|
||||||
|
.filter(|p| p.exists())
|
||||||
|
.unwrap_or(Path::new(&home).join(".nix-profile")),
|
||||||
None => Path::new("/nix/var/nix/profiles/per-user/default").into(),
|
None => Path::new("/nix/var/nix/profiles/per-user/default").into(),
|
||||||
};
|
};
|
||||||
debug!("nix profile: {:?}", profile_path);
|
debug!("nix profile: {:?}", profile_path);
|
||||||
@@ -441,10 +450,9 @@ pub fn run_nix(ctx: &ExecutionContext) -> Result<()> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let run_type = ctx.run_type();
|
ctx.execute(nix_channel).arg("--update").status_checked()?;
|
||||||
run_type.execute(nix_channel).arg("--update").status_checked()?;
|
|
||||||
|
|
||||||
let mut get_version_cmd = ctx.run_type().execute(&nix);
|
let mut get_version_cmd = ctx.execute(&nix);
|
||||||
get_version_cmd.arg("--version");
|
get_version_cmd.arg("--version");
|
||||||
let get_version_cmd_output = get_version_cmd.output_checked_utf8()?;
|
let get_version_cmd_output = get_version_cmd.output_checked_utf8()?;
|
||||||
let get_version_cmd_first_line_stdout = get_version_cmd_output
|
let get_version_cmd_first_line_stdout = get_version_cmd_output
|
||||||
@@ -461,28 +469,31 @@ pub fn run_nix(ctx: &ExecutionContext) -> Result<()> {
|
|||||||
"`nix --version` output"
|
"`nix --version` output"
|
||||||
);
|
);
|
||||||
|
|
||||||
lazy_static! {
|
static NIX_VERSION_REGEX: LazyLock<Regex> =
|
||||||
static ref NIX_VERSION_REGEX: Regex =
|
LazyLock::new(|| 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() {
|
||||||
return Err(eyre!("`nix --version` output was empty"));
|
return Err(eyre!("`nix --version` output was empty"));
|
||||||
}
|
}
|
||||||
|
|
||||||
let captures = NIX_VERSION_REGEX.captures(get_version_cmd_first_line_stdout);
|
let captures = NIX_VERSION_REGEX
|
||||||
let raw_version = match &captures {
|
.captures(get_version_cmd_first_line_stdout)
|
||||||
None => {
|
.ok_or_else(|| eyre!(output_changed_message!("nix --version", "regex did not match")))?;
|
||||||
return Err(eyre!(
|
let raw_version = &captures[1];
|
||||||
"`nix --version` output was weird: {get_version_cmd_first_line_stdout:?}\n\
|
|
||||||
If the `nix --version` output format changed, please file an issue to Topgrade"
|
debug!("Raw Nix version: {raw_version}");
|
||||||
));
|
|
||||||
}
|
// Nix 2.29.0 outputs "2.29" instead of "2.29.0", so we need to add that if necessary.
|
||||||
Some(captures) => &captures[1],
|
let corrected_raw_version = if raw_version.chars().filter(|&c| c == '.').count() == 1 {
|
||||||
|
&format!("{raw_version}.0")
|
||||||
|
} else {
|
||||||
|
raw_version
|
||||||
};
|
};
|
||||||
|
|
||||||
let version =
|
debug!("Corrected raw Nix version: {corrected_raw_version}");
|
||||||
Version::parse(raw_version).wrap_err_with(|| format!("Unable to parse Nix version: {raw_version:?}"))?;
|
|
||||||
|
let version = Version::parse(corrected_raw_version)
|
||||||
|
.wrap_err_with(|| output_changed_message!("nix --version", "Invalid version"))?;
|
||||||
|
|
||||||
debug!("Nix version: {:?}", version);
|
debug!("Nix version: {:?}", version);
|
||||||
|
|
||||||
@@ -495,8 +506,7 @@ pub fn run_nix(ctx: &ExecutionContext) -> Result<()> {
|
|||||||
};
|
};
|
||||||
|
|
||||||
if Path::new(&manifest_json_path).exists() {
|
if Path::new(&manifest_json_path).exists() {
|
||||||
run_type
|
ctx.execute(nix)
|
||||||
.execute(nix)
|
|
||||||
.args(nix_args())
|
.args(nix_args())
|
||||||
.arg("profile")
|
.arg("profile")
|
||||||
.arg("upgrade")
|
.arg("upgrade")
|
||||||
@@ -504,7 +514,7 @@ pub fn run_nix(ctx: &ExecutionContext) -> Result<()> {
|
|||||||
.arg("--verbose")
|
.arg("--verbose")
|
||||||
.status_checked()
|
.status_checked()
|
||||||
} else {
|
} else {
|
||||||
let mut command = run_type.execute(nix_env);
|
let mut command = ctx.execute(nix_env);
|
||||||
command.arg("--upgrade");
|
command.arg("--upgrade");
|
||||||
if let Some(args) = ctx.config().nix_env_arguments() {
|
if let Some(args) = ctx.config().nix_env_arguments() {
|
||||||
command.args(args.split_whitespace());
|
command.args(args.split_whitespace());
|
||||||
@@ -540,21 +550,50 @@ pub fn run_nix_self_upgrade(ctx: &ExecutionContext) -> Result<()> {
|
|||||||
|
|
||||||
print_separator(t!("Nix (self-upgrade)"));
|
print_separator(t!("Nix (self-upgrade)"));
|
||||||
|
|
||||||
|
let version_output = ctx.execute(&nix).arg("--version").output_checked_utf8()?;
|
||||||
|
let version = version_output
|
||||||
|
.stdout
|
||||||
|
.lines()
|
||||||
|
.next()
|
||||||
|
.ok_or_else(|| eyre!("`nix --version` output is empty"))?;
|
||||||
|
|
||||||
|
let is_determinate_nix = version.contains("Determinate Nix");
|
||||||
|
|
||||||
|
debug!(
|
||||||
|
output=%version_output,
|
||||||
|
?is_determinate_nix,
|
||||||
|
"`nix --version` output"
|
||||||
|
);
|
||||||
|
|
||||||
|
if is_determinate_nix {
|
||||||
|
let nixd = require("determinate-nixd");
|
||||||
|
let nixd = match nixd {
|
||||||
|
Err(_) => {
|
||||||
|
println!("Found Determinate Nix, but could not find determinate-nixd");
|
||||||
|
return Err(StepFailed.into());
|
||||||
|
}
|
||||||
|
Ok(nixd) => nixd,
|
||||||
|
};
|
||||||
|
|
||||||
|
let sudo = ctx.require_sudo()?;
|
||||||
|
return sudo
|
||||||
|
.execute_opts(ctx, nixd, SudoExecuteOpts::new().login_shell())?
|
||||||
|
.arg("upgrade")
|
||||||
|
.status_checked();
|
||||||
|
}
|
||||||
|
|
||||||
let multi_user = fs::metadata(&nix)?.uid() == 0;
|
let multi_user = fs::metadata(&nix)?.uid() == 0;
|
||||||
debug!("Multi user nix: {}", multi_user);
|
debug!("Multi user nix: {}", multi_user);
|
||||||
|
|
||||||
let nix_args = nix_args();
|
let nix_args = nix_args();
|
||||||
if multi_user {
|
if multi_user {
|
||||||
ctx.execute_elevated(&nix, true)?
|
let sudo = ctx.require_sudo()?;
|
||||||
|
sudo.execute_opts(ctx, &nix, SudoExecuteOpts::new().login_shell())?
|
||||||
.args(nix_args)
|
.args(nix_args)
|
||||||
.arg("upgrade-nix")
|
.arg("upgrade-nix")
|
||||||
.status_checked()
|
.status_checked()
|
||||||
} else {
|
} else {
|
||||||
ctx.run_type()
|
ctx.execute(&nix).args(nix_args).arg("upgrade-nix").status_checked()
|
||||||
.execute(&nix)
|
|
||||||
.args(nix_args)
|
|
||||||
.arg("upgrade-nix")
|
|
||||||
.status_checked()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -620,6 +659,84 @@ fn nix_profile_dir(nix: &Path) -> Result<Option<PathBuf>> {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Returns a directory from an environment variable, if and only if it is a directory which
|
||||||
|
/// contains a flake.nix
|
||||||
|
fn flake_dir(var: &'static str) -> Option<PathBuf> {
|
||||||
|
std::env::var_os(var)
|
||||||
|
.map(PathBuf::from)
|
||||||
|
.take_if(|x| std::fs::exists(x.join("flake.nix")).is_ok_and(|x| x))
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Update NixOS and home-manager through a flake using `nh`
|
||||||
|
///
|
||||||
|
/// See: https://github.com/viperML/nh
|
||||||
|
pub fn run_nix_helper(ctx: &ExecutionContext) -> Result<()> {
|
||||||
|
require("nix")?;
|
||||||
|
let nix_helper = require("nh")?;
|
||||||
|
|
||||||
|
let fallback_flake_path = flake_dir("NH_FLAKE");
|
||||||
|
let darwin_flake_path = flake_dir("NH_DARWIN_FLAKE");
|
||||||
|
let home_flake_path = flake_dir("NH_HOME_FLAKE");
|
||||||
|
let nixos_flake_path = flake_dir("NH_OS_FLAKE");
|
||||||
|
|
||||||
|
let all_flake_paths: Vec<_> = [
|
||||||
|
fallback_flake_path.as_ref(),
|
||||||
|
darwin_flake_path.as_ref(),
|
||||||
|
home_flake_path.as_ref(),
|
||||||
|
nixos_flake_path.as_ref(),
|
||||||
|
]
|
||||||
|
.into_iter()
|
||||||
|
.flatten()
|
||||||
|
.collect();
|
||||||
|
|
||||||
|
// if none of the paths exist AND contain a `flake.nix`, skip
|
||||||
|
if all_flake_paths.is_empty() {
|
||||||
|
if flake_dir("FLAKE").is_some() {
|
||||||
|
warn!(
|
||||||
|
"{}",
|
||||||
|
t!("You have a flake inside of $FLAKE. This is deprecated for nh.")
|
||||||
|
);
|
||||||
|
}
|
||||||
|
return Err(SkipStep(t!("nh cannot find any configured flakes").into()).into());
|
||||||
|
}
|
||||||
|
|
||||||
|
let nh_switch = |ty: &'static str| -> Result<()> {
|
||||||
|
print_separator(format!("nh {ty}"));
|
||||||
|
|
||||||
|
let mut cmd = ctx.execute(&nix_helper);
|
||||||
|
cmd.arg(ty);
|
||||||
|
cmd.arg("switch");
|
||||||
|
cmd.arg("-u");
|
||||||
|
|
||||||
|
if !ctx.config().yes(Step::NixHelper) {
|
||||||
|
cmd.arg("--ask");
|
||||||
|
}
|
||||||
|
cmd.status_checked()?;
|
||||||
|
Ok(())
|
||||||
|
};
|
||||||
|
|
||||||
|
// We assume that if the user has set these variables, we can throw an error if nh cannot find
|
||||||
|
// a flake there. So we do not anymore perform an eval check to find out whether we should skip
|
||||||
|
// or not.
|
||||||
|
#[cfg(target_os = "macos")]
|
||||||
|
if darwin_flake_path.is_some() || fallback_flake_path.is_some() {
|
||||||
|
nh_switch("darwin")?;
|
||||||
|
}
|
||||||
|
|
||||||
|
if home_flake_path.is_some() || fallback_flake_path.is_some() {
|
||||||
|
nh_switch("home")?;
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(target_os = "linux")]
|
||||||
|
if matches!(Distribution::detect(), Ok(Distribution::NixOS))
|
||||||
|
&& (nixos_flake_path.is_some() || fallback_flake_path.is_some())
|
||||||
|
{
|
||||||
|
nh_switch("os")?;
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
fn nix_args() -> [&'static str; 2] {
|
fn nix_args() -> [&'static str; 2] {
|
||||||
["--extra-experimental-features", "nix-command"]
|
["--extra-experimental-features", "nix-command"]
|
||||||
}
|
}
|
||||||
@@ -629,7 +746,7 @@ pub fn run_yadm(ctx: &ExecutionContext) -> Result<()> {
|
|||||||
|
|
||||||
print_separator("yadm");
|
print_separator("yadm");
|
||||||
|
|
||||||
ctx.run_type().execute(yadm).arg("pull").status_checked()
|
ctx.execute(yadm).arg("pull").status_checked()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn run_asdf(ctx: &ExecutionContext) -> Result<()> {
|
pub fn run_asdf(ctx: &ExecutionContext) -> Result<()> {
|
||||||
@@ -648,26 +765,28 @@ pub fn run_asdf(ctx: &ExecutionContext) -> Result<()> {
|
|||||||
// v0.15.0-31e8c93
|
// v0.15.0-31e8c93
|
||||||
//
|
//
|
||||||
// ```
|
// ```
|
||||||
|
// ```
|
||||||
|
// $ asdf version
|
||||||
|
// v0.16.7
|
||||||
|
// ```
|
||||||
|
// ```
|
||||||
|
// $ asdf version
|
||||||
|
// 0.18.0 (revision unknown)
|
||||||
|
// ```
|
||||||
let version_stdout = version_output.stdout.trim();
|
let version_stdout = version_output.stdout.trim();
|
||||||
// trim the starting 'v'
|
// trim the starting 'v'
|
||||||
let mut remaining = version_stdout.trim_start_matches('v');
|
let mut remaining = version_stdout.trim_start_matches('v');
|
||||||
let idx = remaining
|
// remove the hash or revision part if present
|
||||||
.find('-')
|
if let Some(idx) = remaining.find(['-', ' ']) {
|
||||||
.expect("the output of `asdf version` changed, please file an issue to Topgrade");
|
remaining = &remaining[..idx];
|
||||||
// remove the hash part
|
}
|
||||||
remaining = &remaining[..idx];
|
let version =
|
||||||
let version = Version::parse(remaining).expect("should be a valid version");
|
Version::parse(remaining).wrap_err_with(|| output_changed_message!("asdf version", "invalid version"))?;
|
||||||
if version < Version::new(0, 15, 0) {
|
if version < Version::new(0, 15, 0) {
|
||||||
ctx.run_type()
|
ctx.execute(&asdf).arg("update").status_checked_with_codes(&[42])?;
|
||||||
.execute(&asdf)
|
|
||||||
.arg("update")
|
|
||||||
.status_checked_with_codes(&[42])?;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ctx.run_type()
|
ctx.execute(&asdf).args(["plugin", "update", "--all"]).status_checked()
|
||||||
.execute(&asdf)
|
|
||||||
.args(["plugin", "update", "--all"])
|
|
||||||
.status_checked()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn run_mise(ctx: &ExecutionContext) -> Result<()> {
|
pub fn run_mise(ctx: &ExecutionContext) -> Result<()> {
|
||||||
@@ -675,12 +794,9 @@ pub fn run_mise(ctx: &ExecutionContext) -> Result<()> {
|
|||||||
|
|
||||||
print_separator("mise");
|
print_separator("mise");
|
||||||
|
|
||||||
ctx.run_type()
|
ctx.execute(&mise).args(["plugins", "update"]).status_checked()?;
|
||||||
.execute(&mise)
|
|
||||||
.args(["plugins", "update"])
|
|
||||||
.status_checked()?;
|
|
||||||
|
|
||||||
ctx.run_type().execute(&mise).arg("upgrade").status_checked()
|
ctx.execute(&mise).arg("upgrade").status_checked()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn run_home_manager(ctx: &ExecutionContext) -> Result<()> {
|
pub fn run_home_manager(ctx: &ExecutionContext) -> Result<()> {
|
||||||
@@ -688,7 +804,7 @@ pub fn run_home_manager(ctx: &ExecutionContext) -> Result<()> {
|
|||||||
|
|
||||||
print_separator("home-manager");
|
print_separator("home-manager");
|
||||||
|
|
||||||
let mut cmd = ctx.run_type().execute(home_manager);
|
let mut cmd = ctx.execute(home_manager);
|
||||||
cmd.arg("switch");
|
cmd.arg("switch");
|
||||||
|
|
||||||
if let Some(extra_args) = ctx.config().home_manager() {
|
if let Some(extra_args) = ctx.config().home_manager() {
|
||||||
@@ -698,18 +814,11 @@ pub fn run_home_manager(ctx: &ExecutionContext) -> Result<()> {
|
|||||||
cmd.status_checked()
|
cmd.status_checked()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn run_tldr(ctx: &ExecutionContext) -> Result<()> {
|
|
||||||
let tldr = require("tldr")?;
|
|
||||||
|
|
||||||
print_separator("TLDR");
|
|
||||||
ctx.run_type().execute(tldr).arg("--update").status_checked()
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn run_pearl(ctx: &ExecutionContext) -> Result<()> {
|
pub fn run_pearl(ctx: &ExecutionContext) -> Result<()> {
|
||||||
let pearl = require("pearl")?;
|
let pearl = require("pearl")?;
|
||||||
print_separator("pearl");
|
print_separator("pearl");
|
||||||
|
|
||||||
ctx.run_type().execute(pearl).arg("update").status_checked()
|
ctx.execute(pearl).arg("update").status_checked()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn run_pyenv(ctx: &ExecutionContext) -> Result<()> {
|
pub fn run_pyenv(ctx: &ExecutionContext) -> Result<()> {
|
||||||
@@ -730,7 +839,7 @@ pub fn run_pyenv(ctx: &ExecutionContext) -> Result<()> {
|
|||||||
return Err(SkipStep(t!("pyenv-update plugin is not installed").to_string()).into());
|
return Err(SkipStep(t!("pyenv-update plugin is not installed").to_string()).into());
|
||||||
}
|
}
|
||||||
|
|
||||||
ctx.run_type().execute(pyenv).arg("update").status_checked()
|
ctx.execute(pyenv).arg("update").status_checked()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn run_sdkman(ctx: &ExecutionContext) -> Result<()> {
|
pub fn run_sdkman(ctx: &ExecutionContext) -> Result<()> {
|
||||||
@@ -759,34 +868,25 @@ pub fn run_sdkman(ctx: &ExecutionContext) -> Result<()> {
|
|||||||
|
|
||||||
if selfupdate_enabled == "true" {
|
if selfupdate_enabled == "true" {
|
||||||
let cmd_selfupdate = format!("source {} && sdk selfupdate", &sdkman_init_path);
|
let cmd_selfupdate = format!("source {} && sdk selfupdate", &sdkman_init_path);
|
||||||
ctx.run_type()
|
ctx.execute(&bash)
|
||||||
.execute(&bash)
|
|
||||||
.args(["-c", cmd_selfupdate.as_str()])
|
.args(["-c", cmd_selfupdate.as_str()])
|
||||||
.status_checked()?;
|
.status_checked()?;
|
||||||
}
|
}
|
||||||
|
|
||||||
let cmd_update = format!("source {} && sdk update", &sdkman_init_path);
|
let cmd_update = format!("source {} && sdk update", &sdkman_init_path);
|
||||||
ctx.run_type()
|
ctx.execute(&bash).args(["-c", cmd_update.as_str()]).status_checked()?;
|
||||||
.execute(&bash)
|
|
||||||
.args(["-c", cmd_update.as_str()])
|
|
||||||
.status_checked()?;
|
|
||||||
|
|
||||||
let cmd_upgrade = format!("source {} && sdk upgrade", &sdkman_init_path);
|
let cmd_upgrade = format!("source {} && sdk upgrade", &sdkman_init_path);
|
||||||
ctx.run_type()
|
ctx.execute(&bash).args(["-c", cmd_upgrade.as_str()]).status_checked()?;
|
||||||
.execute(&bash)
|
|
||||||
.args(["-c", cmd_upgrade.as_str()])
|
|
||||||
.status_checked()?;
|
|
||||||
|
|
||||||
if ctx.config().cleanup() {
|
if ctx.config().cleanup() {
|
||||||
let cmd_flush_archives = format!("source {} && sdk flush archives", &sdkman_init_path);
|
let cmd_flush_archives = format!("source {} && sdk flush archives", &sdkman_init_path);
|
||||||
ctx.run_type()
|
ctx.execute(&bash)
|
||||||
.execute(&bash)
|
|
||||||
.args(["-c", cmd_flush_archives.as_str()])
|
.args(["-c", cmd_flush_archives.as_str()])
|
||||||
.status_checked()?;
|
.status_checked()?;
|
||||||
|
|
||||||
let cmd_flush_temp = format!("source {} && sdk flush temp", &sdkman_init_path);
|
let cmd_flush_temp = format!("source {} && sdk flush temp", &sdkman_init_path);
|
||||||
ctx.run_type()
|
ctx.execute(&bash)
|
||||||
.execute(&bash)
|
|
||||||
.args(["-c", cmd_flush_temp.as_str()])
|
.args(["-c", cmd_flush_temp.as_str()])
|
||||||
.status_checked()?;
|
.status_checked()?;
|
||||||
}
|
}
|
||||||
@@ -807,7 +907,7 @@ pub fn run_bun_packages(ctx: &ExecutionContext) -> Result<()> {
|
|||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
|
|
||||||
ctx.run_type().execute(bun).args(["-g", "update"]).status_checked()
|
ctx.execute(bun).args(["-g", "update"]).status_checked()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Update dotfiles with `rcm(7)`.
|
/// Update dotfiles with `rcm(7)`.
|
||||||
@@ -817,18 +917,27 @@ pub fn run_rcm(ctx: &ExecutionContext) -> Result<()> {
|
|||||||
let rcup = require("rcup")?;
|
let rcup = require("rcup")?;
|
||||||
|
|
||||||
print_separator("rcm");
|
print_separator("rcm");
|
||||||
ctx.run_type().execute(rcup).arg("-v").status_checked()
|
ctx.execute(rcup).arg("-v").status_checked()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn run_maza(ctx: &ExecutionContext) -> Result<()> {
|
pub fn run_maza(ctx: &ExecutionContext) -> Result<()> {
|
||||||
let maza = require("maza")?;
|
let maza = require("maza")?;
|
||||||
|
|
||||||
print_separator("maza");
|
print_separator("maza");
|
||||||
ctx.run_type().execute(maza).arg("update").status_checked()
|
ctx.execute(maza).arg("update").status_checked()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn reboot() -> Result<()> {
|
pub fn run_atuin(ctx: &ExecutionContext) -> Result<()> {
|
||||||
print!("{}", t!("Rebooting..."));
|
let atuin = require("atuin-update")?;
|
||||||
|
|
||||||
Command::new("sudo").arg("reboot").status_checked()
|
print_separator("atuin");
|
||||||
|
|
||||||
|
ctx.execute(atuin).status_checked()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn reboot(ctx: &ExecutionContext) -> Result<()> {
|
||||||
|
match ctx.sudo() {
|
||||||
|
Some(sudo) => sudo.execute(ctx, "reboot")?.status_checked(),
|
||||||
|
None => ctx.execute("reboot").status_checked(),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,15 +3,16 @@ use std::{ffi::OsStr, process::Command};
|
|||||||
|
|
||||||
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 tracing::debug;
|
use tracing::debug;
|
||||||
|
|
||||||
use crate::command::CommandExt;
|
use crate::command::CommandExt;
|
||||||
|
use crate::config::UpdatesAutoReboot;
|
||||||
use crate::execution_context::ExecutionContext;
|
use crate::execution_context::ExecutionContext;
|
||||||
|
use crate::step::Step;
|
||||||
use crate::terminal::{print_separator, print_warning};
|
use crate::terminal::{print_separator, print_warning};
|
||||||
use crate::utils::{require, which};
|
use crate::utils::{require, which};
|
||||||
use crate::{error::SkipStep, steps::git::RepoStep};
|
use crate::{error::SkipStep, steps::git::RepoStep};
|
||||||
use crate::{powershell, Step};
|
|
||||||
use rust_i18n::t;
|
|
||||||
|
|
||||||
pub fn run_chocolatey(ctx: &ExecutionContext) -> Result<()> {
|
pub fn run_chocolatey(ctx: &ExecutionContext) -> Result<()> {
|
||||||
let choco = require("choco")?;
|
let choco = require("choco")?;
|
||||||
@@ -19,15 +20,9 @@ pub fn run_chocolatey(ctx: &ExecutionContext) -> Result<()> {
|
|||||||
|
|
||||||
print_separator("Chocolatey");
|
print_separator("Chocolatey");
|
||||||
|
|
||||||
let mut command = match ctx.sudo() {
|
let sudo = ctx.require_sudo()?;
|
||||||
Some(sudo) => {
|
|
||||||
let mut command = ctx.run_type().execute(sudo);
|
|
||||||
command.arg(choco);
|
|
||||||
command
|
|
||||||
}
|
|
||||||
None => ctx.run_type().execute(choco),
|
|
||||||
};
|
|
||||||
|
|
||||||
|
let mut command = sudo.execute(ctx, &choco)?;
|
||||||
command.args(["upgrade", "all"]);
|
command.args(["upgrade", "all"]);
|
||||||
|
|
||||||
if yes {
|
if yes {
|
||||||
@@ -42,12 +37,23 @@ pub fn run_winget(ctx: &ExecutionContext) -> Result<()> {
|
|||||||
|
|
||||||
print_separator("winget");
|
print_separator("winget");
|
||||||
|
|
||||||
|
ctx.execute(&winget).args(["source", "update"]).status_checked()?;
|
||||||
|
|
||||||
|
let mut command = if ctx.config().winget_use_sudo() {
|
||||||
|
let sudo = ctx.require_sudo()?;
|
||||||
|
sudo.execute(ctx, &winget)?
|
||||||
|
} else {
|
||||||
|
ctx.execute(winget)
|
||||||
|
};
|
||||||
|
|
||||||
let mut args = vec!["upgrade", "--all"];
|
let mut args = vec!["upgrade", "--all"];
|
||||||
if ctx.config().winget_silent_install() {
|
if ctx.config().winget_silent_install() {
|
||||||
args.push("--silent");
|
args.push("--silent");
|
||||||
}
|
}
|
||||||
|
|
||||||
ctx.run_type().execute(winget).args(args).status_checked()
|
command.args(args).status_checked()?;
|
||||||
|
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn run_scoop(ctx: &ExecutionContext) -> Result<()> {
|
pub fn run_scoop(ctx: &ExecutionContext) -> Result<()> {
|
||||||
@@ -55,17 +61,13 @@ pub fn run_scoop(ctx: &ExecutionContext) -> Result<()> {
|
|||||||
|
|
||||||
print_separator("Scoop");
|
print_separator("Scoop");
|
||||||
|
|
||||||
ctx.run_type().execute(&scoop).args(["update"]).status_checked()?;
|
ctx.execute(&scoop).args(["update"]).status_checked()?;
|
||||||
ctx.run_type().execute(&scoop).args(["update", "*"]).status_checked()?;
|
ctx.execute(&scoop).args(["update", "*"]).status_checked()?;
|
||||||
|
|
||||||
if ctx.config().cleanup() {
|
if ctx.config().cleanup() {
|
||||||
ctx.run_type().execute(&scoop).args(["cleanup", "*"]).status_checked()?;
|
ctx.execute(&scoop).args(["cleanup", "*"]).status_checked()?;
|
||||||
ctx.run_type()
|
ctx.execute(&scoop).args(["cache", "rm", "-a"]).status_checked()?
|
||||||
.execute(&scoop)
|
|
||||||
.args(["cache", "rm", "-a"])
|
|
||||||
.status_checked()?
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -78,7 +80,7 @@ pub fn update_wsl(ctx: &ExecutionContext) -> Result<()> {
|
|||||||
|
|
||||||
print_separator(t!("Update WSL"));
|
print_separator(t!("Update WSL"));
|
||||||
|
|
||||||
let mut wsl_command = ctx.run_type().execute(wsl);
|
let mut wsl_command = ctx.execute(wsl);
|
||||||
wsl_command.args(["--update"]);
|
wsl_command.args(["--update"]);
|
||||||
|
|
||||||
if ctx.config().wsl_update_pre_release() {
|
if ctx.config().wsl_update_pre_release() {
|
||||||
@@ -95,7 +97,7 @@ pub fn update_wsl(ctx: &ExecutionContext) -> Result<()> {
|
|||||||
/// Detect if WSL is installed or not.
|
/// Detect if WSL is installed or not.
|
||||||
///
|
///
|
||||||
/// For WSL, we cannot simply check if command `wsl` is installed as on newer
|
/// For WSL, we cannot simply check if command `wsl` is installed as on newer
|
||||||
/// versions of Windows (since windows 10 version 2004), this commmand is
|
/// versions of Windows (since windows 10 version 2004), this command is
|
||||||
/// installed by default.
|
/// installed by default.
|
||||||
///
|
///
|
||||||
/// If the command is installed and the user hasn't installed any Linux distros
|
/// If the command is installed and the user hasn't installed any Linux distros
|
||||||
@@ -120,8 +122,8 @@ fn get_wsl_distributions(wsl: &Path) -> Result<Vec<String>> {
|
|||||||
let output = Command::new(wsl).args(["--list", "-q"]).output_checked_utf8()?.stdout;
|
let output = Command::new(wsl).args(["--list", "-q"]).output_checked_utf8()?.stdout;
|
||||||
Ok(output
|
Ok(output
|
||||||
.lines()
|
.lines()
|
||||||
|
.map(|x| x.replace(['\u{0}', '\r'], "").trim().to_owned())
|
||||||
.filter(|s| !s.is_empty())
|
.filter(|s| !s.is_empty())
|
||||||
.map(|x| x.replace(['\u{0}', '\r'], ""))
|
|
||||||
.collect())
|
.collect())
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -134,7 +136,7 @@ fn upgrade_wsl_distribution(wsl: &Path, dist: &str, ctx: &ExecutionContext) -> R
|
|||||||
.trim_end()
|
.trim_end()
|
||||||
.to_owned();
|
.to_owned();
|
||||||
|
|
||||||
let mut command = ctx.run_type().execute(wsl);
|
let mut command = ctx.execute(wsl);
|
||||||
|
|
||||||
// The `arg` method automatically quotes its arguments.
|
// The `arg` method automatically quotes its arguments.
|
||||||
// This means we can't append additional arguments to `topgrade` in WSL
|
// This means we can't append additional arguments to `topgrade` in WSL
|
||||||
@@ -144,12 +146,12 @@ fn upgrade_wsl_distribution(wsl: &Path, dist: &str, ctx: &ExecutionContext) -> R
|
|||||||
//
|
//
|
||||||
// ```rust
|
// ```rust
|
||||||
// command
|
// command
|
||||||
// .args(["-d", dist, "bash", "-c"])
|
// .args(["-d", dist, "bash", "-lc"])
|
||||||
// .arg(format!("TOPGRADE_PREFIX={dist} exec {topgrade}"));
|
// .arg(format!("TOPGRADE_PREFIX={dist} exec {topgrade}"));
|
||||||
// ```
|
// ```
|
||||||
//
|
//
|
||||||
// creates a command string like:
|
// creates a command string like:
|
||||||
// > `C:\WINDOWS\system32\wsl.EXE -d Ubuntu bash -c 'TOPGRADE_PREFIX=Ubuntu exec /bin/topgrade'`
|
// > `C:\WINDOWS\system32\wsl.EXE -d Ubuntu bash -lc 'TOPGRADE_PREFIX=Ubuntu exec /bin/topgrade'`
|
||||||
//
|
//
|
||||||
// Adding the following:
|
// Adding the following:
|
||||||
//
|
//
|
||||||
@@ -158,7 +160,7 @@ fn upgrade_wsl_distribution(wsl: &Path, dist: &str, ctx: &ExecutionContext) -> R
|
|||||||
// ```
|
// ```
|
||||||
//
|
//
|
||||||
// appends the next argument like so:
|
// appends the next argument like so:
|
||||||
// > `C:\WINDOWS\system32\wsl.EXE -d Ubuntu bash -c 'TOPGRADE_PREFIX=Ubuntu exec /bin/topgrade' -v`
|
// > `C:\WINDOWS\system32\wsl.EXE -d Ubuntu bash -lc 'TOPGRADE_PREFIX=Ubuntu exec /bin/topgrade' -v`
|
||||||
// which means `-v` isn't passed to `topgrade`.
|
// which means `-v` isn't passed to `topgrade`.
|
||||||
let mut args = String::new();
|
let mut args = String::new();
|
||||||
if ctx.config().verbose() {
|
if ctx.config().verbose() {
|
||||||
@@ -166,7 +168,7 @@ fn upgrade_wsl_distribution(wsl: &Path, dist: &str, ctx: &ExecutionContext) -> R
|
|||||||
}
|
}
|
||||||
|
|
||||||
command
|
command
|
||||||
.args(["-d", dist, "bash", "-c"])
|
.args(["-d", dist, "bash", "-lc"])
|
||||||
.arg(format!("TOPGRADE_PREFIX={dist} exec {topgrade} {args}"));
|
.arg(format!("TOPGRADE_PREFIX={dist} exec {topgrade} {args}"));
|
||||||
|
|
||||||
if ctx.config().yes(Step::Wsl) {
|
if ctx.config().yes(Step::Wsl) {
|
||||||
@@ -201,40 +203,74 @@ pub fn run_wsl_topgrade(ctx: &ExecutionContext) -> Result<()> {
|
|||||||
if ran {
|
if ran {
|
||||||
Ok(())
|
Ok(())
|
||||||
} else {
|
} else {
|
||||||
Err(SkipStep(t!("Could not find Topgrade in any WSL disribution").to_string()).into())
|
Err(SkipStep(t!("Could not find Topgrade in any WSL distribution").to_string()).into())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn windows_update(ctx: &ExecutionContext) -> Result<()> {
|
pub fn windows_update(ctx: &ExecutionContext) -> Result<()> {
|
||||||
let powershell = powershell::Powershell::windows_powershell();
|
let powershell = ctx.require_powershell()?;
|
||||||
|
|
||||||
print_separator(t!("Windows Update"));
|
print_separator(t!("Windows Update"));
|
||||||
|
|
||||||
if powershell.supports_windows_update() {
|
if !powershell.has_module("PSWindowsUpdate") {
|
||||||
println!("The installer will request to run as administrator, expect a prompt.");
|
|
||||||
|
|
||||||
powershell.windows_update(ctx)
|
|
||||||
} else {
|
|
||||||
print_warning(t!(
|
print_warning(t!(
|
||||||
"Consider installing PSWindowsUpdate as the use of Windows Update via USOClient is not supported."
|
"The PSWindowsUpdate PowerShell module isn't installed so Topgrade can't run Windows Update.\nInstall PSWindowsUpdate by running `Install-Module PSWindowsUpdate` in PowerShell."
|
||||||
));
|
));
|
||||||
|
|
||||||
Err(SkipStep(t!("USOClient not supported.").to_string()).into())
|
return Err(SkipStep(t!("PSWindowsUpdate is not installed").to_string()).into());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let mut cmd = "Import-Module PSWindowsUpdate; Install-WindowsUpdate -Verbose".to_string();
|
||||||
|
|
||||||
|
if ctx.config().accept_all_windows_updates() {
|
||||||
|
cmd.push_str(" -AcceptAll");
|
||||||
|
}
|
||||||
|
|
||||||
|
match ctx.config().windows_updates_auto_reboot() {
|
||||||
|
UpdatesAutoReboot::Yes => cmd.push_str(" -AutoReboot"),
|
||||||
|
UpdatesAutoReboot::No => cmd.push_str(" -IgnoreReboot"),
|
||||||
|
UpdatesAutoReboot::Ask => (), // Prompting is the default for Install-WindowsUpdate
|
||||||
|
}
|
||||||
|
|
||||||
|
powershell.build_command(ctx, &cmd, true)?.status_checked()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn microsoft_store(ctx: &ExecutionContext) -> Result<()> {
|
pub fn microsoft_store(ctx: &ExecutionContext) -> Result<()> {
|
||||||
let powershell = powershell::Powershell::windows_powershell();
|
let powershell = ctx.require_powershell()?;
|
||||||
|
|
||||||
print_separator(t!("Microsoft Store"));
|
print_separator(t!("Microsoft Store"));
|
||||||
|
|
||||||
powershell.microsoft_store(ctx)
|
println!("{}", t!("Scanning for updates..."));
|
||||||
|
|
||||||
|
// Scan for updates using the MDM UpdateScanMethod
|
||||||
|
// This method is also available for non-MDM devices
|
||||||
|
let cmd = r#"(Get-CimInstance -Namespace "Root\cimv2\mdm\dmmap" -ClassName "MDM_EnterpriseModernAppManagement_AppManagement01" | Invoke-CimMethod -MethodName UpdateScanMethod).ReturnValue"#;
|
||||||
|
|
||||||
|
powershell
|
||||||
|
.build_command(ctx, cmd, true)?
|
||||||
|
.output_checked_with_utf8(|output| {
|
||||||
|
if !output.status.success() {
|
||||||
|
return Err(());
|
||||||
|
}
|
||||||
|
let ret_val = output.stdout.trim();
|
||||||
|
debug!("Command return value: {}", ret_val);
|
||||||
|
if ret_val == "0" {
|
||||||
|
Ok(())
|
||||||
|
} else {
|
||||||
|
Err(())
|
||||||
|
}
|
||||||
|
})?;
|
||||||
|
println!(
|
||||||
|
"{}",
|
||||||
|
t!("Success, Microsoft Store apps are being updated in the background")
|
||||||
|
);
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn reboot() -> Result<()> {
|
pub fn reboot(ctx: &ExecutionContext) -> Result<()> {
|
||||||
// If this works, it won't return, but if it doesn't work, it may return a useful error
|
// If this works, it won't return, but if it doesn't work, it may return a useful error
|
||||||
// message.
|
// message.
|
||||||
Command::new("shutdown").args(["/R", "/T", "0"]).status_checked()
|
ctx.execute("shutdown.exe").args(["/R", "/T", "0"]).status_checked()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn insert_startup_scripts(git_repos: &mut RepoStep) -> Result<()> {
|
pub fn insert_startup_scripts(git_repos: &mut RepoStep) -> Result<()> {
|
||||||
|
|||||||
@@ -1,161 +1,159 @@
|
|||||||
#[cfg(windows)]
|
|
||||||
use std::path::Path;
|
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
use std::process::Command;
|
use std::process::Command;
|
||||||
|
|
||||||
|
#[cfg(windows)]
|
||||||
|
use color_eyre::eyre::eyre;
|
||||||
use color_eyre::eyre::Result;
|
use color_eyre::eyre::Result;
|
||||||
use rust_i18n::t;
|
use tracing::debug;
|
||||||
|
|
||||||
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;
|
||||||
use crate::utils::{require_option, which};
|
use crate::utils::{which, PathExt};
|
||||||
use crate::Step;
|
|
||||||
|
|
||||||
pub struct Powershell {
|
pub struct Powershell {
|
||||||
path: Option<PathBuf>,
|
path: PathBuf,
|
||||||
profile: Option<PathBuf>,
|
profile: Option<PathBuf>,
|
||||||
|
is_pwsh: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Powershell {
|
impl Powershell {
|
||||||
/// Returns a powershell instance.
|
pub fn new() -> Option<Self> {
|
||||||
///
|
if terminal::is_dumb() {
|
||||||
/// If the powershell binary is not found, or the current terminal is dumb
|
return None;
|
||||||
/// then the instance of this struct will skip all the powershell steps.
|
|
||||||
pub fn new() -> Self {
|
|
||||||
let path = which("pwsh").or_else(|| which("powershell")).filter(|_| !is_dumb());
|
|
||||||
|
|
||||||
let profile = path.as_ref().and_then(|path| {
|
|
||||||
Command::new(path)
|
|
||||||
.args(["-NoProfile", "-Command", "Split-Path $profile"])
|
|
||||||
.output_checked_utf8()
|
|
||||||
.map(|output| PathBuf::from(output.stdout.trim()))
|
|
||||||
.and_then(super::super::utils::PathExt::require)
|
|
||||||
.ok()
|
|
||||||
});
|
|
||||||
|
|
||||||
Powershell { path, profile }
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(windows)]
|
|
||||||
pub fn windows_powershell() -> Self {
|
|
||||||
Powershell {
|
|
||||||
path: which("powershell").filter(|_| !is_dumb()),
|
|
||||||
profile: None,
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(windows)]
|
let (path, is_pwsh) = which("pwsh")
|
||||||
pub fn has_module(powershell: &Path, command: &str) -> bool {
|
.map(|p| (Some(p), true))
|
||||||
Command::new(powershell)
|
.or_else(|| which("powershell").map(|p| (Some(p), false)))
|
||||||
.args([
|
.unwrap_or((None, false));
|
||||||
"-NoProfile",
|
|
||||||
"-Command",
|
path.map(|path| {
|
||||||
&format!("Get-Module -ListAvailable {command}"),
|
let mut ret = Self {
|
||||||
])
|
path,
|
||||||
.output_checked_utf8()
|
profile: None,
|
||||||
.map(|result| !result.stdout.is_empty())
|
is_pwsh,
|
||||||
.unwrap_or(false)
|
};
|
||||||
|
ret.set_profile();
|
||||||
|
ret
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn profile(&self) -> Option<&PathBuf> {
|
pub fn profile(&self) -> Option<&PathBuf> {
|
||||||
self.profile.as_ref()
|
self.profile.as_ref()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn update_modules(&self, ctx: &ExecutionContext) -> Result<()> {
|
fn set_profile(&mut self) {
|
||||||
let powershell = require_option(self.path.as_ref(), t!("Powershell is not installed").to_string())?;
|
let profile = self
|
||||||
|
.build_command_internal("Split-Path $PROFILE")
|
||||||
|
.output_checked_utf8()
|
||||||
|
.map(|output| output.stdout.trim().to_string())
|
||||||
|
.and_then(|s| PathBuf::from(s).require())
|
||||||
|
.ok();
|
||||||
|
debug!("Found PowerShell profile: {:?}", profile);
|
||||||
|
self.profile = profile;
|
||||||
|
}
|
||||||
|
|
||||||
print_separator(t!("Powershell Modules Update"));
|
pub fn is_pwsh(&self) -> bool {
|
||||||
|
self.is_pwsh
|
||||||
|
}
|
||||||
|
|
||||||
let mut cmd = vec!["Update-Module"];
|
/// Builds an "internal" powershell command
|
||||||
|
pub fn build_command_internal(&self, cmd: &str) -> Command {
|
||||||
|
let mut command = Command::new(&self.path);
|
||||||
|
|
||||||
if ctx.config().verbose() {
|
command.args(["-NoProfile", "-Command"]);
|
||||||
cmd.push("-Verbose");
|
command.arg(cmd);
|
||||||
|
|
||||||
|
// If topgrade was run from pwsh, but we are trying to run powershell, then
|
||||||
|
// the inherited PSModulePath breaks module imports
|
||||||
|
if !self.is_pwsh {
|
||||||
|
command.env_remove("PSModulePath");
|
||||||
}
|
}
|
||||||
|
|
||||||
if ctx.config().yes(Step::Powershell) {
|
command
|
||||||
cmd.push("-Force");
|
}
|
||||||
|
|
||||||
|
/// Builds a "primary" powershell command (uses dry-run if required):
|
||||||
|
/// {powershell} -NoProfile -Command {cmd}
|
||||||
|
pub fn build_command<'a>(
|
||||||
|
&self,
|
||||||
|
ctx: &'a ExecutionContext,
|
||||||
|
cmd: &str,
|
||||||
|
use_sudo: bool,
|
||||||
|
) -> Result<impl CommandExt + 'a> {
|
||||||
|
let mut command = if use_sudo {
|
||||||
|
let sudo = ctx.require_sudo()?;
|
||||||
|
sudo.execute(ctx, &self.path)?
|
||||||
|
} else {
|
||||||
|
ctx.execute(&self.path)
|
||||||
|
};
|
||||||
|
|
||||||
|
#[cfg(windows)]
|
||||||
|
{
|
||||||
|
// Check execution policy and return early if it's not set correctly
|
||||||
|
self.execution_policy_args_if_needed()?;
|
||||||
}
|
}
|
||||||
|
|
||||||
println!("{}", t!("Updating modules..."));
|
command.args(["-NoProfile", "-Command"]);
|
||||||
ctx.run_type()
|
command.arg(cmd);
|
||||||
.execute(powershell)
|
|
||||||
// This probably doesn't need `shell_words::join`.
|
// If topgrade was run from pwsh, but we are trying to run powershell, then
|
||||||
.args(["-NoProfile", "-Command", &cmd.join(" ")])
|
// the inherited PSModulePath breaks module imports
|
||||||
.status_checked()
|
if !self.is_pwsh {
|
||||||
|
command.env_remove("PSModulePath");
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(command)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(windows)]
|
#[cfg(windows)]
|
||||||
pub fn supports_windows_update(&self) -> bool {
|
fn execution_policy_args_if_needed(&self) -> Result<()> {
|
||||||
self.path
|
if !self.is_execution_policy_set("RemoteSigned") {
|
||||||
.as_ref()
|
Err(eyre!(
|
||||||
.map(|p| Self::has_module(p, "PSWindowsUpdate"))
|
"PowerShell execution policy is too restrictive. \
|
||||||
|
Please run 'Set-ExecutionPolicy RemoteSigned -Scope CurrentUser' in PowerShell \
|
||||||
|
(or use Unrestricted/Bypass if you're sure about the security implications)"
|
||||||
|
))
|
||||||
|
} else {
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(windows)]
|
||||||
|
fn is_execution_policy_set(&self, policy: &str) -> bool {
|
||||||
|
// These policies are ordered from most restrictive to least restrictive
|
||||||
|
let valid_policies = ["Restricted", "AllSigned", "RemoteSigned", "Unrestricted", "Bypass"];
|
||||||
|
|
||||||
|
// Find the index of our target policy
|
||||||
|
let target_idx = valid_policies.iter().position(|&p| p == policy);
|
||||||
|
|
||||||
|
let current_policy = self
|
||||||
|
.build_command_internal("Get-ExecutionPolicy")
|
||||||
|
.output_checked_utf8()
|
||||||
|
.map(|output| output.stdout.trim().to_string());
|
||||||
|
|
||||||
|
debug!("Found PowerShell ExecutionPolicy: {:?}", current_policy);
|
||||||
|
|
||||||
|
current_policy.is_ok_and(|current_policy| {
|
||||||
|
// Find the index of the current policy
|
||||||
|
let current_idx = valid_policies.iter().position(|&p| p == current_policy);
|
||||||
|
|
||||||
|
// Check if current policy exists and is at least as permissive as the target
|
||||||
|
match (current_idx, target_idx) {
|
||||||
|
(Some(current), Some(target)) => current >= target,
|
||||||
|
_ => false,
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(windows)]
|
||||||
|
pub fn has_module(&self, module_name: &str) -> bool {
|
||||||
|
let cmd = format!("Get-Module -ListAvailable {}", module_name);
|
||||||
|
|
||||||
|
self.build_command_internal(&cmd)
|
||||||
|
.output_checked()
|
||||||
|
.map(|output| !output.stdout.trim_ascii().is_empty())
|
||||||
.unwrap_or(false)
|
.unwrap_or(false)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(windows)]
|
|
||||||
pub fn windows_update(&self, ctx: &ExecutionContext) -> Result<()> {
|
|
||||||
let powershell = require_option(self.path.as_ref(), t!("Powershell is not installed").to_string())?;
|
|
||||||
|
|
||||||
debug_assert!(self.supports_windows_update());
|
|
||||||
|
|
||||||
let accept_all = if ctx.config().accept_all_windows_updates() {
|
|
||||||
"-AcceptAll"
|
|
||||||
} else {
|
|
||||||
""
|
|
||||||
};
|
|
||||||
|
|
||||||
let install_windowsupdate_verbose = "Install-WindowsUpdate -Verbose".to_string();
|
|
||||||
|
|
||||||
let mut command = if let Some(sudo) = ctx.sudo() {
|
|
||||||
let mut command = ctx.run_type().execute(sudo);
|
|
||||||
command.arg(powershell);
|
|
||||||
command
|
|
||||||
} else {
|
|
||||||
ctx.run_type().execute(powershell)
|
|
||||||
};
|
|
||||||
|
|
||||||
command
|
|
||||||
.args(["-NoProfile", &install_windowsupdate_verbose, accept_all])
|
|
||||||
.status_checked()
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(windows)]
|
|
||||||
pub fn microsoft_store(&self, ctx: &ExecutionContext) -> Result<()> {
|
|
||||||
let powershell = require_option(self.path.as_ref(), t!("Powershell is not installed").to_string())?;
|
|
||||||
|
|
||||||
let mut command = if let Some(sudo) = ctx.sudo() {
|
|
||||||
let mut command = ctx.run_type().execute(sudo);
|
|
||||||
command.arg(powershell);
|
|
||||||
command
|
|
||||||
} else {
|
|
||||||
ctx.run_type().execute(powershell)
|
|
||||||
};
|
|
||||||
|
|
||||||
println!("{}", t!("Scanning for updates..."));
|
|
||||||
|
|
||||||
// Scan for updates using the MDM UpdateScanMethod
|
|
||||||
// This method is also available for non-MDM devices
|
|
||||||
let update_command = "(Get-CimInstance -Namespace \"Root\\cimv2\\mdm\\dmmap\" -ClassName \"MDM_EnterpriseModernAppManagement_AppManagement01\" | Invoke-CimMethod -MethodName UpdateScanMethod).ReturnValue";
|
|
||||||
|
|
||||||
command.args(["-NoProfile", update_command]);
|
|
||||||
|
|
||||||
command
|
|
||||||
.output_checked_with_utf8(|output| {
|
|
||||||
if output.stdout.trim() == "0" {
|
|
||||||
println!(
|
|
||||||
"{}",
|
|
||||||
t!("Success, Microsoft Store apps are being updated in the background")
|
|
||||||
);
|
|
||||||
Ok(())
|
|
||||||
} else {
|
|
||||||
println!(
|
|
||||||
"{}",
|
|
||||||
t!("Unable to update Microsoft Store apps, manual intervention is required")
|
|
||||||
);
|
|
||||||
Err(())
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.map(|_| ())
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -35,7 +35,7 @@ pub fn ssh_step(ctx: &ExecutionContext, hostname: &str) -> Result<()> {
|
|||||||
unreachable!("Tmux execution is only implemented in Unix");
|
unreachable!("Tmux execution is only implemented in Unix");
|
||||||
} else if ctx.config().open_remotes_in_new_terminal() && !ctx.run_type().dry() && cfg!(windows) {
|
} else if ctx.config().open_remotes_in_new_terminal() && !ctx.run_type().dry() && cfg!(windows) {
|
||||||
prepare_async_ssh_command(&mut args);
|
prepare_async_ssh_command(&mut args);
|
||||||
ctx.run_type().execute("wt").args(&args).spawn()?;
|
ctx.execute("wt").args(&args).spawn()?;
|
||||||
Err(SkipStep(String::from(t!("Remote Topgrade launched in an external terminal"))).into())
|
Err(SkipStep(String::from(t!("Remote Topgrade launched in an external terminal"))).into())
|
||||||
} else {
|
} else {
|
||||||
let mut args = vec!["-t", hostname];
|
let mut args = vec!["-t", hostname];
|
||||||
@@ -50,6 +50,6 @@ pub fn ssh_step(ctx: &ExecutionContext, hostname: &str) -> Result<()> {
|
|||||||
print_separator(format!("Remote ({hostname})"));
|
print_separator(format!("Remote ({hostname})"));
|
||||||
println!("{}", t!("Connecting to {hostname}...", hostname = hostname));
|
println!("{}", t!("Connecting to {hostname}...", hostname = hostname));
|
||||||
|
|
||||||
ctx.run_type().execute(ssh).args(&args).status_checked()
|
ctx.execute(ssh).args(&args).status_checked()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -10,8 +10,9 @@ use tracing::{debug, error};
|
|||||||
|
|
||||||
use crate::command::CommandExt;
|
use crate::command::CommandExt;
|
||||||
use crate::execution_context::ExecutionContext;
|
use crate::execution_context::ExecutionContext;
|
||||||
|
use crate::step::Step;
|
||||||
use crate::terminal::print_separator;
|
use crate::terminal::print_separator;
|
||||||
use crate::{error::SkipStep, utils, Step};
|
use crate::{error::SkipStep, utils};
|
||||||
|
|
||||||
#[derive(Debug, Copy, Clone, EnumString)]
|
#[derive(Debug, Copy, Clone, EnumString)]
|
||||||
#[strum(serialize_all = "lowercase")]
|
#[strum(serialize_all = "lowercase")]
|
||||||
@@ -113,8 +114,7 @@ impl<'a> TemporaryPowerOn<'a> {
|
|||||||
BoxStatus::Running => unreachable!(),
|
BoxStatus::Running => unreachable!(),
|
||||||
};
|
};
|
||||||
|
|
||||||
ctx.run_type()
|
ctx.execute(vagrant)
|
||||||
.execute(vagrant)
|
|
||||||
.args([subcommand, &vagrant_box.name])
|
.args([subcommand, &vagrant_box.name])
|
||||||
.current_dir(vagrant_box.path.clone())
|
.current_dir(vagrant_box.path.clone())
|
||||||
.status_checked()?;
|
.status_checked()?;
|
||||||
@@ -140,7 +140,6 @@ impl Drop for TemporaryPowerOn<'_> {
|
|||||||
|
|
||||||
println!();
|
println!();
|
||||||
self.ctx
|
self.ctx
|
||||||
.run_type()
|
|
||||||
.execute(self.vagrant)
|
.execute(self.vagrant)
|
||||||
.args([subcommand, &self.vagrant_box.name])
|
.args([subcommand, &self.vagrant_box.name])
|
||||||
.current_dir(self.vagrant_box.path.clone())
|
.current_dir(self.vagrant_box.path.clone())
|
||||||
@@ -180,7 +179,7 @@ pub fn topgrade_vagrant_box(ctx: &ExecutionContext, vagrant_box: &VagrantBox) ->
|
|||||||
path: utils::require("vagrant")?,
|
path: utils::require("vagrant")?,
|
||||||
};
|
};
|
||||||
|
|
||||||
let seperator = format!("Vagrant ({})", vagrant_box.smart_name());
|
let separator = format!("Vagrant ({})", vagrant_box.smart_name());
|
||||||
let mut _poweron = None;
|
let mut _poweron = None;
|
||||||
if !vagrant_box.initial_status.powered_on() {
|
if !vagrant_box.initial_status.powered_on() {
|
||||||
if !(ctx.config().vagrant_power_on().unwrap_or(true)) {
|
if !(ctx.config().vagrant_power_on().unwrap_or(true)) {
|
||||||
@@ -190,19 +189,18 @@ pub fn topgrade_vagrant_box(ctx: &ExecutionContext, vagrant_box: &VagrantBox) ->
|
|||||||
))
|
))
|
||||||
.into());
|
.into());
|
||||||
} else {
|
} else {
|
||||||
print_separator(seperator);
|
print_separator(separator);
|
||||||
_poweron = Some(vagrant.temporary_power_on(vagrant_box, ctx)?);
|
_poweron = Some(vagrant.temporary_power_on(vagrant_box, ctx)?);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
print_separator(seperator);
|
print_separator(separator);
|
||||||
}
|
}
|
||||||
let mut command = format!("env TOPGRADE_PREFIX={} topgrade", vagrant_box.smart_name());
|
let mut command = format!("env TOPGRADE_PREFIX={} topgrade", vagrant_box.smart_name());
|
||||||
if ctx.config().yes(Step::Vagrant) {
|
if ctx.config().yes(Step::Vagrant) {
|
||||||
command.push_str(" -y");
|
command.push_str(" -y");
|
||||||
}
|
}
|
||||||
|
|
||||||
ctx.run_type()
|
ctx.execute(&vagrant.path)
|
||||||
.execute(&vagrant.path)
|
|
||||||
.current_dir(&vagrant_box.path)
|
.current_dir(&vagrant_box.path)
|
||||||
.args(["ssh", "-c", &command])
|
.args(["ssh", "-c", &command])
|
||||||
.status_checked()
|
.status_checked()
|
||||||
@@ -222,7 +220,6 @@ pub fn upgrade_vagrant_boxes(ctx: &ExecutionContext) -> Result<()> {
|
|||||||
for ele in re.captures_iter(&outdated.stdout) {
|
for ele in re.captures_iter(&outdated.stdout) {
|
||||||
found = true;
|
found = true;
|
||||||
let _ = ctx
|
let _ = ctx
|
||||||
.run_type()
|
|
||||||
.execute(&vagrant)
|
.execute(&vagrant)
|
||||||
.args(["box", "update", "--box"])
|
.args(["box", "update", "--box"])
|
||||||
.arg(ele.get(1).unwrap().as_str())
|
.arg(ele.get(1).unwrap().as_str())
|
||||||
@@ -234,10 +231,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.execute(&vagrant).args(["box", "prune"]).status_checked()?;
|
||||||
.execute(&vagrant)
|
|
||||||
.args(["box", "prune"])
|
|
||||||
.status_checked()?;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
|
|||||||
@@ -5,34 +5,50 @@ use std::process::Command;
|
|||||||
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 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;
|
|
||||||
use crate::{
|
use crate::{
|
||||||
execution_context::ExecutionContext,
|
execution_context::ExecutionContext,
|
||||||
utils::{which, PathExt},
|
utils::{which, PathExt},
|
||||||
};
|
};
|
||||||
|
use crate::{HOME_DIR, XDG_DIRS};
|
||||||
|
|
||||||
use rust_i18n::t;
|
use rust_i18n::t;
|
||||||
#[cfg(unix)]
|
#[cfg(unix)]
|
||||||
use std::os::unix::process::CommandExt as _;
|
use std::os::unix::process::CommandExt as _;
|
||||||
|
|
||||||
|
// update_plugins path is relative to the TPM path
|
||||||
|
const UPDATE_PLUGINS: &str = "bin/update_plugins";
|
||||||
|
// Default TPM path relative to the TMux config directory
|
||||||
|
const TPM_PATH: &str = "plugins/tpm";
|
||||||
|
|
||||||
pub fn run_tpm(ctx: &ExecutionContext) -> Result<()> {
|
pub fn run_tpm(ctx: &ExecutionContext) -> Result<()> {
|
||||||
let tpm = match env::var("TMUX_PLUGIN_MANAGER_PATH") {
|
let tpm = match env::var("TMUX_PLUGIN_MANAGER_PATH") {
|
||||||
// If `TMUX_PLUGIN_MANAGER_PATH` is set, search for
|
// Use `$TMUX_PLUGIN_MANAGER_PATH` if set,
|
||||||
// `$TMUX_PLUGIN_MANAGER_PATH/bin/install_plugins/tpm/bin/update_plugins`
|
Ok(var) => PathBuf::from(var).join(UPDATE_PLUGINS),
|
||||||
Ok(var) => PathBuf::from(var).join("bin/install_plugins/tpm/bin/update_plugins"),
|
Err(_) => {
|
||||||
// Otherwise, use the default location `~/.tmux/plugins/tpm/bin/update_plugins`
|
// otherwise, use the default XDG location `~/.config/tmux`
|
||||||
Err(_) => HOME_DIR.join(".tmux/plugins/tpm/bin/update_plugins"),
|
#[cfg(unix)]
|
||||||
|
let xdg_path = XDG_DIRS.config_dir().join("tmux").join(TPM_PATH).join(UPDATE_PLUGINS);
|
||||||
|
#[cfg(windows)]
|
||||||
|
let xdg_path = HOME_DIR.join(".config/tmux").join(TPM_PATH).join(UPDATE_PLUGINS);
|
||||||
|
if xdg_path.exists() {
|
||||||
|
xdg_path
|
||||||
|
} else {
|
||||||
|
// or fallback on the standard default location `~/.tmux`.
|
||||||
|
HOME_DIR.join(".tmux").join(TPM_PATH).join(UPDATE_PLUGINS)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
.require()?;
|
.require()?;
|
||||||
|
|
||||||
print_separator("tmux plugins");
|
print_separator("tmux plugins");
|
||||||
|
|
||||||
ctx.run_type().execute(tpm).arg("all").status_checked()
|
ctx.execute(tpm).arg("all").status_checked()
|
||||||
}
|
}
|
||||||
|
|
||||||
struct Tmux {
|
struct Tmux {
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
use color_eyre::eyre::Result;
|
use color_eyre::eyre::Result;
|
||||||
|
|
||||||
use crate::command::CommandExt;
|
use crate::command::CommandExt;
|
||||||
use crate::config::Step;
|
use crate::step::Step;
|
||||||
use crate::terminal::print_separator;
|
use crate::terminal::print_separator;
|
||||||
use crate::{execution_context::ExecutionContext, utils::require};
|
use crate::{execution_context::ExecutionContext, utils::require};
|
||||||
use std::path::Path;
|
use std::path::Path;
|
||||||
@@ -59,7 +59,7 @@ pub fn run_toolbx(ctx: &ExecutionContext) -> Result<()> {
|
|||||||
args.push("--yes");
|
args.push("--yes");
|
||||||
}
|
}
|
||||||
|
|
||||||
ctx.run_type().execute(&toolbx).args(&args).status_checked()?;
|
ctx.execute(&toolbx).args(&args).status_checked()?;
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
|
|||||||
@@ -80,23 +80,19 @@ pub fn upgrade_ultimate_vimrc(ctx: &ExecutionContext) -> Result<()> {
|
|||||||
|
|
||||||
print_separator(t!("The Ultimate vimrc"));
|
print_separator(t!("The Ultimate vimrc"));
|
||||||
|
|
||||||
ctx.run_type()
|
ctx.execute(&git)
|
||||||
.execute(&git)
|
|
||||||
.current_dir(&config_dir)
|
.current_dir(&config_dir)
|
||||||
.args(["reset", "--hard"])
|
.args(["reset", "--hard"])
|
||||||
.status_checked()?;
|
.status_checked()?;
|
||||||
ctx.run_type()
|
ctx.execute(&git)
|
||||||
.execute(&git)
|
|
||||||
.current_dir(&config_dir)
|
.current_dir(&config_dir)
|
||||||
.args(["clean", "-d", "--force"])
|
.args(["clean", "-d", "--force"])
|
||||||
.status_checked()?;
|
.status_checked()?;
|
||||||
ctx.run_type()
|
ctx.execute(&git)
|
||||||
.execute(&git)
|
|
||||||
.current_dir(&config_dir)
|
.current_dir(&config_dir)
|
||||||
.args(["pull", "--rebase"])
|
.args(["pull", "--rebase"])
|
||||||
.status_checked()?;
|
.status_checked()?;
|
||||||
ctx.run_type()
|
ctx.execute(python)
|
||||||
.execute(python)
|
|
||||||
.current_dir(config_dir)
|
.current_dir(config_dir)
|
||||||
.arg(update_plugins)
|
.arg(update_plugins)
|
||||||
.status_checked()?;
|
.status_checked()?;
|
||||||
@@ -116,8 +112,7 @@ pub fn upgrade_vim(ctx: &ExecutionContext) -> Result<()> {
|
|||||||
|
|
||||||
print_separator("Vim");
|
print_separator("Vim");
|
||||||
upgrade(
|
upgrade(
|
||||||
ctx.run_type()
|
ctx.execute(&vim)
|
||||||
.execute(&vim)
|
|
||||||
.args(["-u"])
|
.args(["-u"])
|
||||||
.arg(vimrc)
|
.arg(vimrc)
|
||||||
.args(["-U", "NONE", "-V1", "-nNesS"])
|
.args(["-U", "NONE", "-V1", "-nNesS"])
|
||||||
@@ -132,8 +127,7 @@ pub fn upgrade_neovim(ctx: &ExecutionContext) -> Result<()> {
|
|||||||
|
|
||||||
print_separator("Neovim");
|
print_separator("Neovim");
|
||||||
upgrade(
|
upgrade(
|
||||||
ctx.run_type()
|
ctx.execute(nvim)
|
||||||
.execute(nvim)
|
|
||||||
.args(["-u"])
|
.args(["-u"])
|
||||||
.arg(nvimrc)
|
.arg(nvimrc)
|
||||||
.args(["--headless", "-V1", "-nS"])
|
.args(["--headless", "-V1", "-nS"])
|
||||||
@@ -147,5 +141,5 @@ pub fn run_voom(ctx: &ExecutionContext) -> Result<()> {
|
|||||||
|
|
||||||
print_separator("voom");
|
print_separator("voom");
|
||||||
|
|
||||||
ctx.run_type().execute(voom).arg("update").status_checked()
|
ctx.execute(voom).arg("update").status_checked()
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -23,10 +23,7 @@ pub fn run_zr(ctx: &ExecutionContext) -> Result<()> {
|
|||||||
print_separator("zr");
|
print_separator("zr");
|
||||||
|
|
||||||
let cmd = format!("source {} && zr --update", zshrc().display());
|
let cmd = format!("source {} && zr --update", zshrc().display());
|
||||||
ctx.run_type()
|
ctx.execute(zsh).args(["-l", "-c", cmd.as_str()]).status_checked()
|
||||||
.execute(zsh)
|
|
||||||
.args(["-l", "-c", cmd.as_str()])
|
|
||||||
.status_checked()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn zdotdir() -> PathBuf {
|
fn zdotdir() -> PathBuf {
|
||||||
@@ -44,8 +41,7 @@ pub fn run_antidote(ctx: &ExecutionContext) -> Result<()> {
|
|||||||
|
|
||||||
print_separator("antidote");
|
print_separator("antidote");
|
||||||
|
|
||||||
ctx.run_type()
|
ctx.execute(zsh)
|
||||||
.execute(zsh)
|
|
||||||
.arg("-c")
|
.arg("-c")
|
||||||
.arg(format!("source {} && antidote update", antidote.display()))
|
.arg(format!("source {} && antidote update", antidote.display()))
|
||||||
.status_checked()
|
.status_checked()
|
||||||
@@ -57,7 +53,7 @@ pub fn run_antibody(ctx: &ExecutionContext) -> Result<()> {
|
|||||||
|
|
||||||
print_separator("antibody");
|
print_separator("antibody");
|
||||||
|
|
||||||
ctx.run_type().execute(antibody).arg("update").status_checked()
|
ctx.execute(antibody).arg("update").status_checked()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn run_antigen(ctx: &ExecutionContext) -> Result<()> {
|
pub fn run_antigen(ctx: &ExecutionContext) -> Result<()> {
|
||||||
@@ -70,10 +66,7 @@ pub fn run_antigen(ctx: &ExecutionContext) -> Result<()> {
|
|||||||
print_separator("antigen");
|
print_separator("antigen");
|
||||||
|
|
||||||
let cmd = format!("source {} && (antigen selfupdate ; antigen update)", zshrc.display());
|
let cmd = format!("source {} && (antigen selfupdate ; antigen update)", zshrc.display());
|
||||||
ctx.run_type()
|
ctx.execute(zsh).args(["-l", "-c", cmd.as_str()]).status_checked()
|
||||||
.execute(zsh)
|
|
||||||
.args(["-l", "-c", cmd.as_str()])
|
|
||||||
.status_checked()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn run_zgenom(ctx: &ExecutionContext) -> Result<()> {
|
pub fn run_zgenom(ctx: &ExecutionContext) -> Result<()> {
|
||||||
@@ -86,10 +79,7 @@ pub fn run_zgenom(ctx: &ExecutionContext) -> Result<()> {
|
|||||||
print_separator("zgenom");
|
print_separator("zgenom");
|
||||||
|
|
||||||
let cmd = format!("source {} && zgenom selfupdate && zgenom update", zshrc.display());
|
let cmd = format!("source {} && zgenom selfupdate && zgenom update", zshrc.display());
|
||||||
ctx.run_type()
|
ctx.execute(zsh).args(["-l", "-c", cmd.as_str()]).status_checked()
|
||||||
.execute(zsh)
|
|
||||||
.args(["-l", "-c", cmd.as_str()])
|
|
||||||
.status_checked()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn run_zplug(ctx: &ExecutionContext) -> Result<()> {
|
pub fn run_zplug(ctx: &ExecutionContext) -> Result<()> {
|
||||||
@@ -102,10 +92,7 @@ pub fn run_zplug(ctx: &ExecutionContext) -> Result<()> {
|
|||||||
|
|
||||||
print_separator("zplug");
|
print_separator("zplug");
|
||||||
|
|
||||||
ctx.run_type()
|
ctx.execute(zsh).args(["-i", "-c", "zplug update"]).status_checked()
|
||||||
.execute(zsh)
|
|
||||||
.args(["-i", "-c", "zplug update"])
|
|
||||||
.status_checked()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn run_zinit(ctx: &ExecutionContext) -> Result<()> {
|
pub fn run_zinit(ctx: &ExecutionContext) -> Result<()> {
|
||||||
@@ -119,10 +106,7 @@ pub fn run_zinit(ctx: &ExecutionContext) -> Result<()> {
|
|||||||
print_separator("zinit");
|
print_separator("zinit");
|
||||||
|
|
||||||
let cmd = format!("source {} && zinit self-update && zinit update --all", zshrc.display());
|
let cmd = format!("source {} && zinit self-update && zinit update --all", zshrc.display());
|
||||||
ctx.run_type()
|
ctx.execute(zsh).args(["-i", "-c", cmd.as_str()]).status_checked()
|
||||||
.execute(zsh)
|
|
||||||
.args(["-i", "-c", cmd.as_str()])
|
|
||||||
.status_checked()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn run_zi(ctx: &ExecutionContext) -> Result<()> {
|
pub fn run_zi(ctx: &ExecutionContext) -> Result<()> {
|
||||||
@@ -134,7 +118,7 @@ pub fn run_zi(ctx: &ExecutionContext) -> Result<()> {
|
|||||||
print_separator("zi");
|
print_separator("zi");
|
||||||
|
|
||||||
let cmd = format!("source {} && zi self-update && zi update --all", zshrc.display());
|
let cmd = format!("source {} && zi self-update && zi update --all", zshrc.display());
|
||||||
ctx.run_type().execute(zsh).args(["-i", "-c", &cmd]).status_checked()
|
ctx.execute(zsh).args(["-i", "-c", &cmd]).status_checked()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn run_zim(ctx: &ExecutionContext) -> Result<()> {
|
pub fn run_zim(ctx: &ExecutionContext) -> Result<()> {
|
||||||
@@ -152,8 +136,7 @@ pub fn run_zim(ctx: &ExecutionContext) -> Result<()> {
|
|||||||
|
|
||||||
print_separator("zim");
|
print_separator("zim");
|
||||||
|
|
||||||
ctx.run_type()
|
ctx.execute(zsh)
|
||||||
.execute(zsh)
|
|
||||||
.args(["-i", "-c", "zimfw upgrade && zimfw update"])
|
.args(["-i", "-c", "zimfw upgrade && zimfw update"])
|
||||||
.status_checked()
|
.status_checked()
|
||||||
}
|
}
|
||||||
@@ -219,8 +202,7 @@ pub fn run_oh_my_zsh(ctx: &ExecutionContext) -> Result<()> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
custom_repos.remove(&oh_my_zsh);
|
custom_repos.remove(&oh_my_zsh);
|
||||||
ctx.run_type()
|
ctx.execute("zsh")
|
||||||
.execute("zsh")
|
|
||||||
.arg(oh_my_zsh.join("tools/upgrade.sh"))
|
.arg(oh_my_zsh.join("tools/upgrade.sh"))
|
||||||
// oh-my-zsh returns 80 when it is already updated and no changes pulled
|
// oh-my-zsh returns 80 when it is already updated and no changes pulled
|
||||||
// in this update.
|
// in this update.
|
||||||
|
|||||||
496
src/sudo.rs
496
src/sudo.rs
@@ -2,12 +2,23 @@ use std::ffi::OsStr;
|
|||||||
use std::path::Path;
|
use std::path::Path;
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
|
|
||||||
|
#[cfg(windows)]
|
||||||
|
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;
|
||||||
|
use rust_i18n::t;
|
||||||
use serde::Deserialize;
|
use serde::Deserialize;
|
||||||
use strum::AsRefStr;
|
use strum::Display;
|
||||||
|
use thiserror::Error;
|
||||||
|
#[cfg(windows)]
|
||||||
|
use tracing::{debug, warn};
|
||||||
|
#[cfg(windows)]
|
||||||
|
use windows::Win32::Foundation::ERROR_FILE_NOT_FOUND;
|
||||||
|
|
||||||
use crate::command::CommandExt;
|
use crate::command::CommandExt;
|
||||||
|
use crate::error::UnsupportedSudo;
|
||||||
use crate::execution_context::ExecutionContext;
|
use crate::execution_context::ExecutionContext;
|
||||||
use crate::executor::Executor;
|
use crate::executor::Executor;
|
||||||
use crate::terminal::print_separator;
|
use crate::terminal::print_separator;
|
||||||
@@ -16,41 +27,241 @@ use crate::utils::which;
|
|||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
pub struct Sudo {
|
pub struct Sudo {
|
||||||
/// The path to the `sudo` binary.
|
/// The path to the `sudo` binary.
|
||||||
path: PathBuf,
|
path: Option<PathBuf>,
|
||||||
/// The type of program being used as `sudo`.
|
/// The type of program being used as `sudo`.
|
||||||
kind: SudoKind,
|
kind: SudoKind,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Sudo {
|
#[derive(Error, Debug)]
|
||||||
/// Get the `sudo` binary or the `gsudo` binary in the case of `gsudo`
|
pub enum SudoCreateError {
|
||||||
/// masquerading as the `sudo` binary.
|
CannotFindBinary,
|
||||||
fn determine_sudo_variant(sudo_p: PathBuf) -> (PathBuf, SudoKind) {
|
#[cfg(windows)]
|
||||||
match which("gsudo") {
|
WinSudoDisabled,
|
||||||
Some(gsudo_p) => {
|
#[cfg(windows)]
|
||||||
match std::fs::canonicalize(&gsudo_p).unwrap() == std::fs::canonicalize(&sudo_p).unwrap() {
|
WinSudoNewWindowMode,
|
||||||
true => (gsudo_p, SudoKind::Gsudo),
|
}
|
||||||
false => (sudo_p, SudoKind::Sudo),
|
|
||||||
}
|
impl std::fmt::Display for SudoCreateError {
|
||||||
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
|
match self {
|
||||||
|
SudoCreateError::CannotFindBinary => {
|
||||||
|
write!(f, "{}", t!("Cannot find sudo binary"))
|
||||||
|
}
|
||||||
|
#[cfg(windows)]
|
||||||
|
SudoCreateError::WinSudoDisabled => {
|
||||||
|
write!(f, "{}", t!("Found Windows Sudo, but it is disabled"))
|
||||||
|
}
|
||||||
|
#[cfg(windows)]
|
||||||
|
SudoCreateError::WinSudoNewWindowMode => {
|
||||||
|
write!(
|
||||||
|
f,
|
||||||
|
"{}",
|
||||||
|
t!("Found Windows Sudo, but it is using 'In a new window' mode")
|
||||||
|
)
|
||||||
}
|
}
|
||||||
None => (sudo_p, SudoKind::Sudo),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Debug, Default)]
|
||||||
|
pub enum SudoPreserveEnv<'a> {
|
||||||
|
/// Preserve all environment variables.
|
||||||
|
All,
|
||||||
|
/// Preserve only the specified environment variables.
|
||||||
|
Some(&'a [&'a str]),
|
||||||
|
/// Preserve no environment variables.
|
||||||
|
#[default]
|
||||||
|
None,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Generic sudo options, translated into flags to pass to `sudo`.
|
||||||
|
/// NOTE: Depending on the sudo kind, OS and system config, some options might be specified by
|
||||||
|
/// default or unsupported.
|
||||||
|
#[derive(Clone, Debug, Default)]
|
||||||
|
pub struct SudoExecuteOpts<'a> {
|
||||||
|
/// Run the command inside a login shell.
|
||||||
|
pub login_shell: bool,
|
||||||
|
/// Preserve environment variables across the sudo call.
|
||||||
|
pub preserve_env: SudoPreserveEnv<'a>,
|
||||||
|
/// Set the HOME environment variable to the target user's home directory.
|
||||||
|
pub set_home: bool,
|
||||||
|
/// Run the command as a user other than the root user.
|
||||||
|
pub user: Option<&'a str>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> SudoExecuteOpts<'a> {
|
||||||
|
pub fn new() -> Self {
|
||||||
|
Self::default()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Run the command inside a login shell.
|
||||||
|
#[allow(unused)]
|
||||||
|
pub fn login_shell(mut self) -> Self {
|
||||||
|
self.login_shell = true;
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Preserve all environment variables across the sudo call.
|
||||||
|
#[allow(unused)]
|
||||||
|
pub fn preserve_env(mut self) -> Self {
|
||||||
|
self.preserve_env = SudoPreserveEnv::All;
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Preserve only the specified environment variables across the sudo call.
|
||||||
|
#[allow(unused)]
|
||||||
|
pub fn preserve_env_list(mut self, vars: &'a [&'a str]) -> Self {
|
||||||
|
self.preserve_env = SudoPreserveEnv::Some(vars);
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Set the HOME environment variable to the target user's home directory.
|
||||||
|
#[allow(unused)]
|
||||||
|
pub fn set_home(mut self) -> Self {
|
||||||
|
self.set_home = true;
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Run the command as a user other than the root user.
|
||||||
|
#[allow(unused)]
|
||||||
|
pub fn user(mut self, user: &'a str) -> Self {
|
||||||
|
self.user = Some(user);
|
||||||
|
self
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(not(windows))]
|
||||||
|
const DETECT_ORDER: [SudoKind; 5] = [
|
||||||
|
SudoKind::Doas,
|
||||||
|
SudoKind::Sudo,
|
||||||
|
SudoKind::Pkexec,
|
||||||
|
SudoKind::Run0,
|
||||||
|
SudoKind::Please,
|
||||||
|
];
|
||||||
|
|
||||||
|
// NOTE: keep WinSudo last, allows short-circuit error return in Sudo::detect() to work
|
||||||
|
#[cfg(windows)]
|
||||||
|
const DETECT_ORDER: [SudoKind; 2] = [SudoKind::Gsudo, SudoKind::WinSudo];
|
||||||
|
|
||||||
|
impl Sudo {
|
||||||
/// Get the `sudo` binary for this platform.
|
/// Get the `sudo` binary for this platform.
|
||||||
pub fn detect() -> Option<Self> {
|
pub fn detect() -> Result<Self, SudoCreateError> {
|
||||||
which("doas")
|
use SudoCreateError::*;
|
||||||
.map(|p| (p, SudoKind::Doas))
|
|
||||||
.or_else(|| which("sudo").map(Self::determine_sudo_variant))
|
for kind in DETECT_ORDER {
|
||||||
.or_else(|| which("gsudo").map(|p| (p, SudoKind::Gsudo)))
|
match Self::new(kind) {
|
||||||
.or_else(|| which("pkexec").map(|p| (p, SudoKind::Pkexec)))
|
Ok(sudo) => return Ok(sudo),
|
||||||
.or_else(|| which("run0").map(|p| (p, SudoKind::Run0)))
|
Err(CannotFindBinary) => continue,
|
||||||
.or_else(|| which("please").map(|p| (p, SudoKind::Please)))
|
#[cfg(windows)]
|
||||||
.map(|(path, kind)| Self { path, kind })
|
Err(e @ (WinSudoDisabled | WinSudoNewWindowMode)) => {
|
||||||
|
// we can return directly here since WinSudo is detected last
|
||||||
|
return Err(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Err(CannotFindBinary)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Create Sudo from SudoKind, if found in the system
|
/// Create Sudo from SudoKind, if found in the system
|
||||||
pub fn new(kind: SudoKind) -> Option<Self> {
|
pub fn new(kind: SudoKind) -> Result<Self, SudoCreateError> {
|
||||||
which(kind.as_ref()).map(|path| Self { path, kind })
|
// no actual binary for null sudo
|
||||||
|
if let SudoKind::Null = kind {
|
||||||
|
return Ok(Self { path: None, kind });
|
||||||
|
}
|
||||||
|
|
||||||
|
match kind.which() {
|
||||||
|
Some(path) => {
|
||||||
|
let sudo = Self { path: Some(path), kind };
|
||||||
|
|
||||||
|
#[cfg(windows)]
|
||||||
|
if let SudoKind::WinSudo = kind {
|
||||||
|
// Windows Sudo might be disabled, causing it to error on use.
|
||||||
|
//
|
||||||
|
// It checks two registry keys to determine its mode:
|
||||||
|
// a "policy" (HLKM\SOFTWARE\Policies\Microsoft\Windows\Sudo\Enabled)
|
||||||
|
// and a "setting" (HLKM\SOFTWARE\Microsoft\Windows\CurrentVersion\Sudo\Enabled).
|
||||||
|
//
|
||||||
|
// Both keys are u32's, with these meanings:
|
||||||
|
// 0 - Disabled
|
||||||
|
// 1 - ForceNewWindow
|
||||||
|
// 2 - DisableInput
|
||||||
|
// 3 - Normal
|
||||||
|
//
|
||||||
|
// Setting the sudo option in Settings changes the setting key, the policy key
|
||||||
|
// sets an upper limit on the setting key: mode = min(policy, setting).
|
||||||
|
// The default for the policy key is 3 (all modes allowed), and the default for
|
||||||
|
// the setting key is 0 (disabled).
|
||||||
|
//
|
||||||
|
// See https://github.com/microsoft/sudo/blob/9f50d79704a9d4d468bc59f725993714762981ca/sudo/src/helpers.rs#L442
|
||||||
|
|
||||||
|
#[derive(Debug, Eq, Ord, PartialEq, PartialOrd)]
|
||||||
|
enum SudoMode {
|
||||||
|
Disabled = 0,
|
||||||
|
ForceNewWindow = 1,
|
||||||
|
DisableInput = 2,
|
||||||
|
Normal = 3,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl TryFrom<u32> for SudoMode {
|
||||||
|
type Error = eyre::Error;
|
||||||
|
|
||||||
|
fn try_from(value: u32) -> Result<Self> {
|
||||||
|
match value {
|
||||||
|
0 => Ok(SudoMode::Disabled),
|
||||||
|
1 => Ok(SudoMode::ForceNewWindow),
|
||||||
|
2 => Ok(SudoMode::DisableInput),
|
||||||
|
3 => Ok(SudoMode::Normal),
|
||||||
|
_ => Err(eyre!("invalid integer SudoMode: {value}")),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_mode(key: &str, on_missing: SudoMode) -> SudoMode {
|
||||||
|
match windows_registry::LOCAL_MACHINE
|
||||||
|
.open(key)
|
||||||
|
.and_then(|k| k.get_u32("Enabled"))
|
||||||
|
{
|
||||||
|
Ok(v) => v.min(3).try_into().unwrap(),
|
||||||
|
Err(e) if e.code() == ERROR_FILE_NOT_FOUND.to_hresult() => on_missing,
|
||||||
|
Err(e) => {
|
||||||
|
// warn, but treat as normal (using sudo should error)
|
||||||
|
warn!(r"Error reading registry key HKLM\{key}\Enabled: {e}");
|
||||||
|
SudoMode::Normal
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// default to normal if key missing
|
||||||
|
let policy_mode = get_mode(r"SOFTWARE\Policies\Microsoft\Windows\Sudo", SudoMode::Normal);
|
||||||
|
debug!("Windows Sudo policy mode: {policy_mode:?}");
|
||||||
|
// default to disabled if key missing
|
||||||
|
let setting_mode = get_mode(r"SOFTWARE\Microsoft\Windows\CurrentVersion\Sudo", SudoMode::Disabled);
|
||||||
|
debug!("Windows Sudo setting mode: {setting_mode:?}");
|
||||||
|
|
||||||
|
let sudo_mode = policy_mode.min(setting_mode);
|
||||||
|
debug!("Windows Sudo mode: {sudo_mode:?}");
|
||||||
|
|
||||||
|
if sudo_mode == SudoMode::Disabled {
|
||||||
|
return Err(SudoCreateError::WinSudoDisabled);
|
||||||
|
} else if sudo_mode == SudoMode::ForceNewWindow {
|
||||||
|
return Err(SudoCreateError::WinSudoNewWindowMode);
|
||||||
|
}
|
||||||
|
// Normal mode is best, but DisableInput doesn't seem to cause issues
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(sudo)
|
||||||
|
}
|
||||||
|
None => Err(SudoCreateError::CannotFindBinary),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Gets the path to the `sudo` binary. Do not use this to execute `sudo` directly - either use
|
||||||
|
/// [`Sudo::elevate`], or if you need to specify arguments to `sudo`, use [`Sudo::elevate_opts`].
|
||||||
|
/// This way, sudo options can be specified generically and the actual arguments customized
|
||||||
|
/// depending on the sudo kind.
|
||||||
|
#[allow(unused)]
|
||||||
|
pub fn path(&self) -> Option<&Path> {
|
||||||
|
self.path.as_deref()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Elevate permissions with `sudo`.
|
/// Elevate permissions with `sudo`.
|
||||||
@@ -60,8 +271,15 @@ impl Sudo {
|
|||||||
///
|
///
|
||||||
/// See: https://github.com/topgrade-rs/topgrade/issues/205
|
/// See: https://github.com/topgrade-rs/topgrade/issues/205
|
||||||
pub fn elevate(&self, ctx: &ExecutionContext) -> Result<()> {
|
pub fn elevate(&self, ctx: &ExecutionContext) -> Result<()> {
|
||||||
|
// skip if using null sudo
|
||||||
|
if let SudoKind::Null = self.kind {
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
|
||||||
print_separator("Sudo");
|
print_separator("Sudo");
|
||||||
let mut cmd = ctx.run_type().execute(self);
|
|
||||||
|
// self.path is only None for null sudo, which we've handled above
|
||||||
|
let mut cmd = ctx.execute(self.path.as_deref().unwrap());
|
||||||
match self.kind {
|
match self.kind {
|
||||||
SudoKind::Doas => {
|
SudoKind::Doas => {
|
||||||
// `doas` doesn't have anything like `sudo -v` to cache credentials,
|
// `doas` doesn't have anything like `sudo -v` to cache credentials,
|
||||||
@@ -79,12 +297,19 @@ impl Sudo {
|
|||||||
// command. Not all security policies support cached credentials.
|
// command. Not all security policies support cached credentials.
|
||||||
cmd.arg("-v");
|
cmd.arg("-v");
|
||||||
}
|
}
|
||||||
|
SudoKind::WinSudo => {
|
||||||
|
// Windows `sudo` doesn't cache credentials, so we just execute a
|
||||||
|
// dummy command - the easiest on Windows is `rem` in cmd.
|
||||||
|
// See: https://learn.microsoft.com/en-us/windows/advanced-settings/sudo/
|
||||||
|
cmd.args(["cmd.exe", "/c", "rem"]);
|
||||||
|
}
|
||||||
SudoKind::Gsudo => {
|
SudoKind::Gsudo => {
|
||||||
// `gsudo` doesn't have anything like `sudo -v` to cache credentials,
|
// `gsudo` doesn't have anything like `sudo -v` to cache credentials,
|
||||||
// so we just execute a dummy `echo` command so we have something
|
// so we just execute a dummy command - the easiest on Windows is
|
||||||
// unobtrusive to run.
|
// `rem` in cmd. `-d` tells it to run the command directly, without
|
||||||
|
// going through a shell (which could be powershell) first.
|
||||||
// See: https://gerardog.github.io/gsudo/docs/usage
|
// See: https://gerardog.github.io/gsudo/docs/usage
|
||||||
cmd.arg("echo");
|
cmd.args(["-d", "cmd.exe", "/c", "rem"]);
|
||||||
}
|
}
|
||||||
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
|
||||||
@@ -109,42 +334,233 @@ impl Sudo {
|
|||||||
// Warm the access token and exit.
|
// Warm the access token and exit.
|
||||||
cmd.arg("-w");
|
cmd.arg("-w");
|
||||||
}
|
}
|
||||||
|
SudoKind::Null => unreachable!(),
|
||||||
}
|
}
|
||||||
cmd.status_checked().wrap_err("Failed to elevate permissions")
|
cmd.status_checked().wrap_err("Failed to elevate permissions")
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Execute a command with `sudo`.
|
/// Execute a command with `sudo`.
|
||||||
pub fn execute_elevated(&self, ctx: &ExecutionContext, command: &Path, interactive: bool) -> Executor {
|
pub fn execute<S: AsRef<OsStr>>(&self, ctx: &ExecutionContext, command: S) -> Result<Executor> {
|
||||||
let mut cmd = ctx.run_type().execute(self);
|
self.execute_opts(ctx, command, SudoExecuteOpts::new())
|
||||||
|
}
|
||||||
|
|
||||||
if let SudoKind::Sudo = self.kind {
|
/// Execute a command with `sudo`, with custom options.
|
||||||
cmd.arg("--preserve-env=DIFFPROG");
|
pub fn execute_opts<S: AsRef<OsStr>>(
|
||||||
|
&self,
|
||||||
|
ctx: &ExecutionContext,
|
||||||
|
command: S,
|
||||||
|
opts: SudoExecuteOpts,
|
||||||
|
) -> Result<Executor> {
|
||||||
|
// null sudo is very different, do separately
|
||||||
|
if let SudoKind::Null = self.kind {
|
||||||
|
if opts.login_shell {
|
||||||
|
// TODO: emulate running in a login shell with su/runuser
|
||||||
|
return Err(UnsupportedSudo {
|
||||||
|
sudo_kind: self.kind,
|
||||||
|
option: "login_shell",
|
||||||
|
}
|
||||||
|
.into());
|
||||||
|
}
|
||||||
|
if opts.user.is_some() {
|
||||||
|
// TODO: emulate running as a different user with su/runuser
|
||||||
|
return Err(UnsupportedSudo {
|
||||||
|
sudo_kind: self.kind,
|
||||||
|
option: "user",
|
||||||
|
}
|
||||||
|
.into());
|
||||||
|
}
|
||||||
|
|
||||||
|
// NOTE: we ignore preserve_env and set_home, using
|
||||||
|
// no sudo effectively preserves these by default
|
||||||
|
|
||||||
|
// run command directly
|
||||||
|
return Ok(ctx.execute(command));
|
||||||
}
|
}
|
||||||
|
|
||||||
if interactive {
|
// self.path is only None for null sudo, which we've handled above
|
||||||
cmd.arg("-i");
|
let mut cmd = ctx.execute(self.path.as_ref().unwrap());
|
||||||
|
|
||||||
|
if opts.login_shell {
|
||||||
|
match self.kind {
|
||||||
|
SudoKind::Sudo => {
|
||||||
|
cmd.arg("-i");
|
||||||
|
}
|
||||||
|
SudoKind::Gsudo => {
|
||||||
|
// By default, gsudo runs all commands inside a shell. If login_shell
|
||||||
|
// is *not* specified, we add `-d` to run outside of a shell - see below.
|
||||||
|
}
|
||||||
|
SudoKind::Doas | SudoKind::WinSudo | SudoKind::Pkexec | SudoKind::Run0 | SudoKind::Please => {
|
||||||
|
return Err(UnsupportedSudo {
|
||||||
|
sudo_kind: self.kind,
|
||||||
|
option: "login_shell",
|
||||||
|
}
|
||||||
|
.into());
|
||||||
|
}
|
||||||
|
SudoKind::Null => unreachable!(),
|
||||||
|
}
|
||||||
|
} else if let SudoKind::Gsudo = self.kind {
|
||||||
|
// The `-d` (direct) flag disables shell detection, running the command directly
|
||||||
|
// rather than through the current shell.
|
||||||
|
// Additionally, if the current shell is pwsh >= 7.3.0, then not including this
|
||||||
|
// gives errors if the command to run has spaces in it: see
|
||||||
|
// https://github.com/gerardog/gsudo/issues/297
|
||||||
|
cmd.arg("-d");
|
||||||
|
}
|
||||||
|
|
||||||
|
match opts.preserve_env {
|
||||||
|
SudoPreserveEnv::All => match self.kind {
|
||||||
|
SudoKind::Sudo => {
|
||||||
|
cmd.arg("-E");
|
||||||
|
}
|
||||||
|
SudoKind::Gsudo => {
|
||||||
|
cmd.arg("--copyEV");
|
||||||
|
}
|
||||||
|
SudoKind::Doas | SudoKind::WinSudo | SudoKind::Pkexec | SudoKind::Run0 | SudoKind::Please => {
|
||||||
|
return Err(UnsupportedSudo {
|
||||||
|
sudo_kind: self.kind,
|
||||||
|
option: "preserve_env",
|
||||||
|
}
|
||||||
|
.into());
|
||||||
|
}
|
||||||
|
SudoKind::Null => unreachable!(),
|
||||||
|
},
|
||||||
|
SudoPreserveEnv::Some(vars) => match self.kind {
|
||||||
|
SudoKind::Sudo => {
|
||||||
|
cmd.arg(format!("--preserve-env={}", vars.join(",")));
|
||||||
|
}
|
||||||
|
SudoKind::Run0 => {
|
||||||
|
for env in vars {
|
||||||
|
cmd.arg(format!("--setenv={}", env));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
SudoKind::Please => {
|
||||||
|
cmd.arg("-a");
|
||||||
|
cmd.arg(vars.join(","));
|
||||||
|
}
|
||||||
|
SudoKind::Doas | SudoKind::WinSudo | SudoKind::Gsudo | SudoKind::Pkexec => {
|
||||||
|
return Err(UnsupportedSudo {
|
||||||
|
sudo_kind: self.kind,
|
||||||
|
option: "preserve_env_list",
|
||||||
|
}
|
||||||
|
.into());
|
||||||
|
}
|
||||||
|
SudoKind::Null => unreachable!(),
|
||||||
|
},
|
||||||
|
SudoPreserveEnv::None => {}
|
||||||
|
}
|
||||||
|
|
||||||
|
if opts.set_home {
|
||||||
|
match self.kind {
|
||||||
|
SudoKind::Sudo => {
|
||||||
|
cmd.arg("-H");
|
||||||
|
}
|
||||||
|
SudoKind::Doas
|
||||||
|
| SudoKind::WinSudo
|
||||||
|
| SudoKind::Gsudo
|
||||||
|
| SudoKind::Pkexec
|
||||||
|
| SudoKind::Run0
|
||||||
|
| SudoKind::Please => {
|
||||||
|
return Err(UnsupportedSudo {
|
||||||
|
sudo_kind: self.kind,
|
||||||
|
option: "set_home",
|
||||||
|
}
|
||||||
|
.into());
|
||||||
|
}
|
||||||
|
SudoKind::Null => unreachable!(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some(user) = opts.user {
|
||||||
|
match self.kind {
|
||||||
|
SudoKind::Sudo => {
|
||||||
|
cmd.args(["-u", user]);
|
||||||
|
}
|
||||||
|
SudoKind::Doas | SudoKind::Gsudo | SudoKind::Run0 | SudoKind::Please => {
|
||||||
|
cmd.args(["-u", user]);
|
||||||
|
}
|
||||||
|
SudoKind::Pkexec => {
|
||||||
|
cmd.args(["--user", user]);
|
||||||
|
}
|
||||||
|
SudoKind::WinSudo => {
|
||||||
|
// Windows sudo is the only one that doesn't have a `-u` flag
|
||||||
|
return Err(UnsupportedSudo {
|
||||||
|
sudo_kind: self.kind,
|
||||||
|
option: "user",
|
||||||
|
}
|
||||||
|
.into());
|
||||||
|
}
|
||||||
|
SudoKind::Null => unreachable!(),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
cmd.arg(command);
|
cmd.arg(command);
|
||||||
|
|
||||||
cmd
|
Ok(cmd)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Copy, Debug, Deserialize, AsRefStr)]
|
// On unix we use `SudoKind::Sudo`, and on windows `SudoKind::WinSudo`.
|
||||||
|
// We always define both though, so that we don't have to put
|
||||||
|
// #[cfg(...)] everywhere.
|
||||||
|
|
||||||
|
#[derive(Clone, Copy, Debug, Display, Deserialize)]
|
||||||
#[serde(rename_all = "lowercase")]
|
#[serde(rename_all = "lowercase")]
|
||||||
#[strum(serialize_all = "lowercase")]
|
#[strum(serialize_all = "lowercase")]
|
||||||
pub enum SudoKind {
|
pub enum SudoKind {
|
||||||
Doas,
|
// On unix, "sudo" in the config file means Sudo
|
||||||
|
#[cfg(not(windows))]
|
||||||
Sudo,
|
Sudo,
|
||||||
|
// and WinSudo is skipped, making it unused.
|
||||||
|
#[cfg(not(windows))]
|
||||||
|
#[expect(unused, reason = "WinSudo is windows-only")]
|
||||||
|
#[serde(skip)]
|
||||||
|
WinSudo,
|
||||||
|
|
||||||
|
// On unix, Sudo is skipped and unused
|
||||||
|
#[cfg(windows)]
|
||||||
|
#[expect(unused, reason = "Sudo is unix-only")]
|
||||||
|
#[serde(skip)]
|
||||||
|
Sudo,
|
||||||
|
// and "sudo" in the config file means WinSudo.
|
||||||
|
#[cfg(windows)]
|
||||||
|
#[serde(rename = "sudo")]
|
||||||
|
WinSudo,
|
||||||
|
|
||||||
|
Doas,
|
||||||
Gsudo,
|
Gsudo,
|
||||||
Pkexec,
|
Pkexec,
|
||||||
Run0,
|
Run0,
|
||||||
Please,
|
Please,
|
||||||
|
/// A "no-op" sudo, used when topgrade itself is running as root
|
||||||
|
Null,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl AsRef<OsStr> for Sudo {
|
impl SudoKind {
|
||||||
fn as_ref(&self) -> &OsStr {
|
/// Get the name of the "sudo" binary.
|
||||||
self.path.as_ref()
|
///
|
||||||
|
/// For `SudoKind::WinSudo`, returns the full hardcoded path
|
||||||
|
/// instead to ensure we find Windows Sudo rather than gsudo
|
||||||
|
/// masquerading as sudo.
|
||||||
|
///
|
||||||
|
/// Only returns `None` for `SudoKind::Null`.
|
||||||
|
fn binary_name(self) -> Option<&'static str> {
|
||||||
|
match self {
|
||||||
|
SudoKind::Doas => Some("doas"),
|
||||||
|
SudoKind::Sudo => Some("sudo"),
|
||||||
|
SudoKind::WinSudo => Some(r"C:\Windows\System32\sudo.exe"),
|
||||||
|
SudoKind::Gsudo => Some("gsudo"),
|
||||||
|
SudoKind::Pkexec => Some("pkexec"),
|
||||||
|
SudoKind::Run0 => Some("run0"),
|
||||||
|
SudoKind::Please => Some("please"),
|
||||||
|
SudoKind::Null => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Find the full path to the "sudo" binary, if it exists on the system.
|
||||||
|
fn which(self) -> Option<PathBuf> {
|
||||||
|
match self.binary_name() {
|
||||||
|
Some(name) => which(name),
|
||||||
|
None => None,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,14 +2,13 @@ use std::cmp::{max, min};
|
|||||||
use std::env;
|
use std::env;
|
||||||
use std::io::{self, Write};
|
use std::io::{self, Write};
|
||||||
use std::process::Command;
|
use std::process::Command;
|
||||||
use std::sync::Mutex;
|
use std::sync::{LazyLock, Mutex};
|
||||||
use std::time::Duration;
|
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::{style, Key, Term};
|
||||||
use lazy_static::lazy_static;
|
|
||||||
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};
|
||||||
@@ -17,11 +16,9 @@ use tracing::{debug, error};
|
|||||||
use which_crate::which;
|
use which_crate::which;
|
||||||
|
|
||||||
use crate::command::CommandExt;
|
use crate::command::CommandExt;
|
||||||
use crate::report::StepResult;
|
use crate::runner::StepResult;
|
||||||
|
|
||||||
lazy_static! {
|
static TERMINAL: LazyLock<Mutex<Terminal>> = LazyLock::new(|| Mutex::new(Terminal::new()));
|
||||||
static ref TERMINAL: Mutex<Terminal> = Mutex::new(Terminal::new());
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(unix)]
|
#[cfg(unix)]
|
||||||
pub fn shell() -> String {
|
pub fn shell() -> String {
|
||||||
@@ -176,6 +173,11 @@ impl Terminal {
|
|||||||
StepResult::Success => format!("{}", style(t!("OK")).bold().green()),
|
StepResult::Success => format!("{}", style(t!("OK")).bold().green()),
|
||||||
StepResult::Failure => format!("{}", style(t!("FAILED")).bold().red()),
|
StepResult::Failure => format!("{}", style(t!("FAILED")).bold().red()),
|
||||||
StepResult::Ignored => format!("{}", style(t!("IGNORED")).bold().yellow()),
|
StepResult::Ignored => format!("{}", style(t!("IGNORED")).bold().yellow()),
|
||||||
|
StepResult::SkippedMissingSudo => format!(
|
||||||
|
"{}: {}",
|
||||||
|
style(t!("SKIPPED")).bold().yellow(),
|
||||||
|
t!("Could not find sudo")
|
||||||
|
),
|
||||||
StepResult::Skipped(reason) => format!("{}: {}", style(t!("SKIPPED")).bold().blue(), reason),
|
StepResult::Skipped(reason) => format!("{}: {}", style(t!("SKIPPED")).bold().blue(), reason),
|
||||||
}
|
}
|
||||||
))
|
))
|
||||||
|
|||||||
61
src/utils.rs
61
src/utils.rs
@@ -112,6 +112,29 @@ pub fn require<T: AsRef<OsStr> + Debug>(binary_name: T) -> Result<PathBuf> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn require_one<T: AsRef<OsStr> + Debug>(binary_names: impl IntoIterator<Item = T>) -> Result<PathBuf> {
|
||||||
|
let mut failed_bins = Vec::new();
|
||||||
|
for bin in binary_names {
|
||||||
|
match require(&bin) {
|
||||||
|
Ok(path) => return Ok(path),
|
||||||
|
Err(_) => failed_bins.push(bin),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Err(SkipStep(format!(
|
||||||
|
"{}",
|
||||||
|
t!(
|
||||||
|
"Cannot find any of {binary_names} in PATH",
|
||||||
|
binary_names = failed_bins
|
||||||
|
.iter()
|
||||||
|
.map(|bin| format!("{:?}", bin))
|
||||||
|
.collect::<Vec<_>>()
|
||||||
|
.join(", ")
|
||||||
|
)
|
||||||
|
))
|
||||||
|
.into())
|
||||||
|
}
|
||||||
|
|
||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
pub fn require_option<T>(option: Option<T>, cause: String) -> Result<T> {
|
pub fn require_option<T>(option: Option<T>, cause: String) -> Result<T> {
|
||||||
if let Some(value) = option {
|
if let Some(value) = option {
|
||||||
@@ -146,6 +169,22 @@ pub fn hostname() -> Result<String> {
|
|||||||
.map(|output| output.stdout.trim().to_owned())
|
.map(|output| output.stdout.trim().to_owned())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(unix)]
|
||||||
|
pub fn is_elevated() -> bool {
|
||||||
|
let euid = nix::unistd::Uid::effective();
|
||||||
|
debug!("Running with euid: {euid}");
|
||||||
|
euid.is_root()
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(windows)]
|
||||||
|
pub fn is_elevated() -> bool {
|
||||||
|
let elevated = is_elevated::is_elevated();
|
||||||
|
if elevated {
|
||||||
|
debug!("Detected elevated process");
|
||||||
|
}
|
||||||
|
elevated
|
||||||
|
}
|
||||||
|
|
||||||
pub mod merge_strategies {
|
pub mod merge_strategies {
|
||||||
use merge::Merge;
|
use merge::Merge;
|
||||||
|
|
||||||
@@ -156,7 +195,7 @@ pub mod merge_strategies {
|
|||||||
if let Some(left_vec) = left {
|
if let Some(left_vec) = left {
|
||||||
if let Some(mut right_vec) = right {
|
if let Some(mut right_vec) = right {
|
||||||
right_vec.append(left_vec);
|
right_vec.append(left_vec);
|
||||||
let _ = std::mem::replace(left, Some(right_vec));
|
let _ = left.replace(right_vec);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
*left = right;
|
*left = right;
|
||||||
@@ -199,17 +238,11 @@ pub mod merge_strategies {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Skip causes
|
|
||||||
// TODO: Put them in a better place when we have more of them
|
|
||||||
pub fn get_require_sudo_string() -> String {
|
|
||||||
t!("Require sudo or counterpart but not found, skip").to_string()
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Return `Err(SkipStep)` if `python` is a Python 2 or shim.
|
/// Return `Err(SkipStep)` if `python` is a Python 2 or shim.
|
||||||
///
|
///
|
||||||
/// # Shim
|
/// # Shim
|
||||||
/// On Windows, if you install `python` through `winget`, an actual `python`
|
/// On Windows, if you install `python` through `winget`, an actual `python`
|
||||||
/// is installed as well as a `python3` shim. Shim is invokable, but when you
|
/// is installed as well as a `python3` shim. Shim is invocable, but when you
|
||||||
/// execute it, the Microsoft App Store will be launched instead of a Python
|
/// execute it, the Microsoft App Store will be launched instead of a Python
|
||||||
/// shell.
|
/// shell.
|
||||||
///
|
///
|
||||||
@@ -282,3 +315,15 @@ pub fn install_color_eyre() -> Result<()> {
|
|||||||
.display_location_section(true)
|
.display_location_section(true)
|
||||||
.install()
|
.install()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Macro to construct an error message for when the output of a command is unexpected.
|
||||||
|
#[macro_export]
|
||||||
|
macro_rules! output_changed_message {
|
||||||
|
($command:expr, $message:expr) => {
|
||||||
|
format!(
|
||||||
|
"The output of `{}` changed: {}. This is not your fault, this is an issue in Topgrade. Please open an issue at: https://github.com/topgrade-rs/topgrade/issues/new?template=bug_report.md",
|
||||||
|
$command,
|
||||||
|
$message,
|
||||||
|
)
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user