Compare commits
58 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
5bd5f10f0c | ||
|
|
bfaca61deb | ||
|
|
b00c4c1503 | ||
|
|
54a722be21 | ||
|
|
bf4555ed29 | ||
|
|
46eb74109e | ||
|
|
0bde798b4a | ||
|
|
ebb4448950 | ||
|
|
b2b51bc8d2 | ||
|
|
8840a273b4 | ||
|
|
50e55dea77 | ||
|
|
f7c9e42066 | ||
|
|
ef3ee7bea7 | ||
|
|
8eb300c4fb | ||
|
|
b7b99a725c | ||
|
|
df090a89c4 | ||
|
|
856fa0ed5b | ||
|
|
9bb5a680ac | ||
|
|
2d40f7bdb3 | ||
|
|
06b210d1c9 | ||
|
|
e0e714e7b5 | ||
|
|
dfb8342d8b | ||
|
|
9d662e36a1 | ||
|
|
45159c29fe | ||
|
|
a27c68a1dd | ||
|
|
cdee1c14d9 | ||
|
|
8de6a36d86 | ||
|
|
b03a8d53bb | ||
|
|
b0510cdade | ||
|
|
7945311b4b | ||
|
|
75de4dfd3b | ||
|
|
6a838bbcb7 | ||
|
|
ab2bab8c9b | ||
|
|
9a55278d32 | ||
|
|
f9735f3b31 | ||
|
|
50be214b56 | ||
|
|
9ec8e83f41 | ||
|
|
c70984d458 | ||
|
|
a3503c0c70 | ||
|
|
ca2d16edfd | ||
|
|
722b1ad09e | ||
|
|
743845a66b | ||
|
|
2594f4c0fb | ||
|
|
639d055f9a | ||
|
|
ea2ccdd69f | ||
|
|
84a50afa83 | ||
|
|
b13c1bd2d7 | ||
|
|
7749f41d56 | ||
|
|
593a2a33d9 | ||
|
|
4f693aeaf3 | ||
|
|
c3d34184d0 | ||
|
|
4aa224de87 | ||
|
|
320b13c06b | ||
|
|
907d778c55 | ||
|
|
f3fccb86c0 | ||
|
|
bb4afb71e9 | ||
|
|
ec8d30f634 | ||
|
|
50d318641a |
31
.github/ISSUE_TEMPLATE/bug_report.md
vendored
31
.github/ISSUE_TEMPLATE/bug_report.md
vendored
@@ -2,7 +2,7 @@
|
|||||||
name: Bug report
|
name: Bug report
|
||||||
about: Topgrade is misbehaving
|
about: Topgrade is misbehaving
|
||||||
title: ''
|
title: ''
|
||||||
labels: 'C-bug'
|
type: Bug
|
||||||
assignees: ''
|
assignees: ''
|
||||||
|
|
||||||
---
|
---
|
||||||
@@ -14,52 +14,65 @@ Please make sure to
|
|||||||
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.
|
||||||
-->
|
-->
|
||||||
|
|
||||||
|
## Checklist
|
||||||
|
|
||||||
|
- [ ] I have searched the issue tracker for relevant or duplicate issues.
|
||||||
|
|
||||||
## 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
|
||||||
- [ ] No
|
- [ ] No
|
||||||
|
|
||||||
## Did you run topgrade through `Remote Execution`
|
## Ran through `Remote Execution`
|
||||||
|
|
||||||
|
<!--
|
||||||
|
Did you run topgrade through `Remote Execution`?
|
||||||
|
-->
|
||||||
|
|
||||||
- [ ] Yes
|
- [ ] Yes
|
||||||
- [ ] No
|
- [ ] No
|
||||||
|
|
||||||
If yes, does the issue still occur when you run topgrade directly 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.
|
||||||
@@ -70,6 +83,7 @@ related to configuration.
|
|||||||
```
|
```
|
||||||
|
|
||||||
## Additional Details
|
## Additional Details
|
||||||
|
|
||||||
- Operation System/Version
|
- Operation System/Version
|
||||||
<!-- For example, Fedora Linux 38 -->
|
<!-- For example, Fedora Linux 38 -->
|
||||||
|
|
||||||
@@ -82,6 +96,7 @@ related to configuration.
|
|||||||
- 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
|
||||||
-->
|
-->
|
||||||
|
|||||||
18
.github/ISSUE_TEMPLATE/feature_request.md
vendored
18
.github/ISSUE_TEMPLATE/feature_request.md
vendored
@@ -1,21 +1,15 @@
|
|||||||
---
|
---
|
||||||
name: Feature request
|
name: General feature request
|
||||||
about: Can you please support...?
|
about: Suggest a general feature, or feature within an already existing step
|
||||||
title: ''
|
title: ''
|
||||||
labels: 'C-feature request'
|
type: Feature
|
||||||
assignees: ''
|
assignees: ''
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## I want to suggest a new step
|
## Checklist
|
||||||
|
|
||||||
* Which tool is this about? Where is its repository?
|
- [ ] I have searched the issue tracker for relevant or duplicate issues.
|
||||||
* Which operating systems are supported by this tool?
|
|
||||||
* What should Topgrade do to figure out if the tool needs to be invoked?
|
|
||||||
* Which exact commands should Topgrade run?
|
|
||||||
* Does it have a `--dry-run` option? i.e., print what should be done and exit
|
|
||||||
* Does it need the user to confirm the execution? And does it provide a `--yes`
|
|
||||||
option to skip this step?
|
|
||||||
|
|
||||||
## I want to suggest some general feature
|
## I want to suggest some general feature
|
||||||
|
|
||||||
@@ -25,3 +19,5 @@ Topgrade should...
|
|||||||
|
|
||||||
<!-- Assuming that someone else implements the feature,
|
<!-- Assuming that someone else implements the feature,
|
||||||
please state if you know how to test it from a side branch of Topgrade. -->
|
please state if you know how to test it from a side branch of Topgrade. -->
|
||||||
|
|
||||||
|
- [ ] I am able and willing to implement this feature myself
|
||||||
|
|||||||
30
.github/ISSUE_TEMPLATE/step_request.md
vendored
Normal file
30
.github/ISSUE_TEMPLATE/step_request.md
vendored
Normal file
@@ -0,0 +1,30 @@
|
|||||||
|
---
|
||||||
|
name: New step request
|
||||||
|
about: Suggest a new step/package manager to update
|
||||||
|
title: ''
|
||||||
|
type: Feature
|
||||||
|
labels: request step
|
||||||
|
assignees: ''
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Checklist
|
||||||
|
|
||||||
|
- [ ] I have searched the issue tracker for relevant or duplicate issues.
|
||||||
|
|
||||||
|
## I want to suggest a new step
|
||||||
|
|
||||||
|
* Which tool is this about? Where is its repository?
|
||||||
|
* Which operating systems are supported by this tool?
|
||||||
|
* What should Topgrade do to figure out if the tool needs to be invoked?
|
||||||
|
* Which exact commands should Topgrade run?
|
||||||
|
* Does it have a `--dry-run` option? i.e., print what should be done and exit
|
||||||
|
* Does it need the user to confirm the execution? And does it provide a `--yes`
|
||||||
|
option to skip this?
|
||||||
|
|
||||||
|
## More information
|
||||||
|
|
||||||
|
<!-- Assuming that someone else implements the step,
|
||||||
|
please state if you know how to test it from a side branch of Topgrade. -->
|
||||||
|
|
||||||
|
- [ ] I am able and willing to implement this step myself
|
||||||
24
.github/dependabot.yml
vendored
24
.github/dependabot.yml
vendored
@@ -1,24 +0,0 @@
|
|||||||
# Set update schedule for GitHub Actions
|
|
||||||
|
|
||||||
version: 2
|
|
||||||
updates:
|
|
||||||
- package-ecosystem: "github-actions"
|
|
||||||
directory: "/"
|
|
||||||
schedule:
|
|
||||||
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"]
|
|
||||||
@@ -15,7 +15,7 @@ jobs:
|
|||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v5.0.0
|
- uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v6.0.0
|
||||||
with:
|
with:
|
||||||
persist-credentials: false
|
persist-credentials: false
|
||||||
|
|
||||||
|
|||||||
2
.github/workflows/check_i18n.yml
vendored
2
.github/workflows/check_i18n.yml
vendored
@@ -14,7 +14,7 @@ jobs:
|
|||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout code
|
- name: Checkout code
|
||||||
uses: actions/checkout@v5.0.0
|
uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v6.0.0
|
||||||
with:
|
with:
|
||||||
persist-credentials: false
|
persist-credentials: false
|
||||||
|
|
||||||
|
|||||||
@@ -24,7 +24,7 @@ jobs:
|
|||||||
security-events: write
|
security-events: write
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout code
|
- name: Checkout code
|
||||||
uses: actions/checkout@v5.0.0
|
uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v6.0.0
|
||||||
with:
|
with:
|
||||||
persist-credentials: false
|
persist-credentials: false
|
||||||
|
|
||||||
@@ -32,6 +32,6 @@ jobs:
|
|||||||
uses: microsoft/DevSkim-Action@4b5047945a44163b94642a1cecc0d93a3f428cc6 # v1.0.16
|
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@v4.31.2
|
uses: github/codeql-action/upload-sarif@e12f0178983d466f2f6028f5cc7a6d786fd97f4b # v4.31.4
|
||||||
with:
|
with:
|
||||||
sarif_file: devskim-results.sarif
|
sarif_file: devskim-results.sarif
|
||||||
|
|||||||
6
.github/workflows/ci.yml
vendored
6
.github/workflows/ci.yml
vendored
@@ -23,7 +23,7 @@ jobs:
|
|||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout code
|
- name: Checkout code
|
||||||
uses: actions/checkout@v5.0.0
|
uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v6.0.0
|
||||||
with:
|
with:
|
||||||
persist-credentials: false
|
persist-credentials: false
|
||||||
|
|
||||||
@@ -39,7 +39,7 @@ jobs:
|
|||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout code
|
- name: Checkout code
|
||||||
uses: actions/checkout@v5.0.0
|
uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v6.0.0
|
||||||
with:
|
with:
|
||||||
persist-credentials: false
|
persist-credentials: false
|
||||||
|
|
||||||
@@ -135,7 +135,7 @@ jobs:
|
|||||||
matrix_target: ${{ matrix.target }}
|
matrix_target: ${{ matrix.target }}
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout code
|
- name: Checkout code
|
||||||
uses: actions/checkout@v5.0.0
|
uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v6.0.0
|
||||||
with:
|
with:
|
||||||
persist-credentials: false
|
persist-credentials: false
|
||||||
|
|
||||||
|
|||||||
8
.github/workflows/create_release_assets.yml
vendored
8
.github/workflows/create_release_assets.yml
vendored
@@ -33,7 +33,7 @@ jobs:
|
|||||||
env:
|
env:
|
||||||
tag: ${{ github.event.client_payload.tag }}
|
tag: ${{ github.event.client_payload.tag }}
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v5.0.0
|
- uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v6.0.0
|
||||||
with:
|
with:
|
||||||
persist-credentials: false
|
persist-credentials: false
|
||||||
|
|
||||||
@@ -137,7 +137,7 @@ jobs:
|
|||||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
|
||||||
- name: Generate artifact attestations
|
- name: Generate artifact attestations
|
||||||
uses: actions/attest-build-provenance@v3.0.0
|
uses: actions/attest-build-provenance@977bb373ede98d70efdf65b84cb5f73e068dcc2a # v3.0.0
|
||||||
with:
|
with:
|
||||||
subject-path: assets/*
|
subject-path: assets/*
|
||||||
|
|
||||||
@@ -169,7 +169,7 @@ jobs:
|
|||||||
matrix_target: ${{ matrix.target }}
|
matrix_target: ${{ matrix.target }}
|
||||||
tag: ${{ github.event.client_payload.tag }}
|
tag: ${{ github.event.client_payload.tag }}
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v5.0.0
|
- uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v6.0.0
|
||||||
with:
|
with:
|
||||||
persist-credentials: false
|
persist-credentials: false
|
||||||
|
|
||||||
@@ -284,7 +284,7 @@ jobs:
|
|||||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
|
||||||
- name: Generate artifact attestations
|
- name: Generate artifact attestations
|
||||||
uses: actions/attest-build-provenance@v3.0.0
|
uses: actions/attest-build-provenance@977bb373ede98d70efdf65b84cb5f73e068dcc2a # v3.0.0
|
||||||
with:
|
with:
|
||||||
subject-path: assets/*
|
subject-path: assets/*
|
||||||
|
|
||||||
|
|||||||
4
.github/workflows/dependency-review.yml
vendored
4
.github/workflows/dependency-review.yml
vendored
@@ -17,9 +17,9 @@ jobs:
|
|||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- name: 'Checkout Repository'
|
- name: 'Checkout Repository'
|
||||||
uses: actions/checkout@v5.0.0
|
uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v6.0.0
|
||||||
with:
|
with:
|
||||||
persist-credentials: false
|
persist-credentials: false
|
||||||
|
|
||||||
- name: 'Dependency Review'
|
- name: 'Dependency Review'
|
||||||
uses: actions/dependency-review-action@40c09b7dc99638e5ddb0bfd91c1673effc064d8a # v4.8.1
|
uses: actions/dependency-review-action@3c4e3dcb1aa7874d2c16be7d79418e9b7efd6261 # v4.8.2
|
||||||
|
|||||||
5
.github/workflows/lint_pr.yml
vendored
5
.github/workflows/lint_pr.yml
vendored
@@ -1,11 +1,12 @@
|
|||||||
name: 'Lint PR'
|
name: 'Lint PR'
|
||||||
|
|
||||||
on:
|
on:
|
||||||
pull_request_target:
|
pull_request_target: # zizmor: ignore[dangerous-triggers] this is the only way, and we're not running user code
|
||||||
types:
|
types:
|
||||||
- opened
|
- opened
|
||||||
- edited
|
- edited
|
||||||
- reopened
|
- reopened
|
||||||
|
- synchronize
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
main:
|
main:
|
||||||
@@ -14,6 +15,6 @@ jobs:
|
|||||||
permissions:
|
permissions:
|
||||||
pull-requests: read
|
pull-requests: read
|
||||||
steps:
|
steps:
|
||||||
- uses: amannn/action-semantic-pull-request@v6.1.1
|
- uses: amannn/action-semantic-pull-request@48f256284bd46cdaab1048c3721360e808335d50 # v6.1.1
|
||||||
env:
|
env:
|
||||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
|||||||
8
.github/workflows/release-plz.yml
vendored
8
.github/workflows/release-plz.yml
vendored
@@ -17,7 +17,7 @@ jobs:
|
|||||||
id-token: write # For trusted publishing
|
id-token: write # For trusted publishing
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout repository
|
- name: Checkout repository
|
||||||
uses: actions/checkout@v5
|
uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v6
|
||||||
with:
|
with:
|
||||||
fetch-depth: 0
|
fetch-depth: 0
|
||||||
persist-credentials: false
|
persist-credentials: false
|
||||||
@@ -25,7 +25,7 @@ jobs:
|
|||||||
uses: dtolnay/rust-toolchain@stable
|
uses: dtolnay/rust-toolchain@stable
|
||||||
- name: Run release-plz
|
- name: Run release-plz
|
||||||
id: release-plz
|
id: release-plz
|
||||||
uses: release-plz/action@v0.5
|
uses: release-plz/action@d529f731ae3e89610ada96eda34e5c6ba3b12214 # v0.5
|
||||||
with:
|
with:
|
||||||
command: release
|
command: release
|
||||||
env:
|
env:
|
||||||
@@ -53,14 +53,14 @@ jobs:
|
|||||||
cancel-in-progress: false
|
cancel-in-progress: false
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout repository
|
- name: Checkout repository
|
||||||
uses: actions/checkout@v5
|
uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v6
|
||||||
with:
|
with:
|
||||||
fetch-depth: 0
|
fetch-depth: 0
|
||||||
persist-credentials: false
|
persist-credentials: false
|
||||||
- name: Install Rust toolchain
|
- name: Install Rust toolchain
|
||||||
uses: dtolnay/rust-toolchain@stable
|
uses: dtolnay/rust-toolchain@stable
|
||||||
- name: Run release-plz
|
- name: Run release-plz
|
||||||
uses: release-plz/action@v0.5
|
uses: release-plz/action@d529f731ae3e89610ada96eda34e5c6ba3b12214 # v0.5
|
||||||
with:
|
with:
|
||||||
command: release-pr
|
command: release-pr
|
||||||
env:
|
env:
|
||||||
|
|||||||
5
.github/workflows/release_to_homebrew.yml
vendored
5
.github/workflows/release_to_homebrew.yml
vendored
@@ -12,10 +12,11 @@ jobs:
|
|||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- name: Bump formulae
|
- name: Bump formulae
|
||||||
uses: dawidd6/action-homebrew-bump-formula@3428a0601bba3173ec0bdcc945be23fa27aa4c31 # v5
|
uses: dawidd6/action-homebrew-bump-formula@c5ddc585e75f0f750a8b4f610688b4bec9e80915 # v6
|
||||||
with:
|
with:
|
||||||
# Custom GitHub access token with only the 'public_repo' scope enabled
|
# Custom GitHub access token with only the 'public_repo' scope enabled
|
||||||
token: ${{secrets.HOMEBREW_ACCESS_TOKEN}}
|
token: ${{secrets.HOMEBREW_ACCESS_TOKEN}}
|
||||||
formula: topgrade
|
formula: topgrade
|
||||||
tag: ${{ github.event.client_payload.tag }}
|
tag: ${{ github.event.client_payload.tag }}
|
||||||
org: topgrade-rs
|
# We cannot use an org because org forks cannot give push access to maintainers, which Homebrew requires.
|
||||||
|
# org: topgrade-rs
|
||||||
|
|||||||
20
.github/workflows/release_to_pypi.yml
vendored
20
.github/workflows/release_to_pypi.yml
vendored
@@ -15,7 +15,7 @@ jobs:
|
|||||||
matrix:
|
matrix:
|
||||||
target: [x86_64, x86, aarch64]
|
target: [x86_64, x86, aarch64]
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v5.0.0
|
- uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v6.0.0
|
||||||
with:
|
with:
|
||||||
persist-credentials: false
|
persist-credentials: false
|
||||||
|
|
||||||
@@ -26,7 +26,7 @@ jobs:
|
|||||||
args: --release --out dist
|
args: --release --out dist
|
||||||
manylinux: auto
|
manylinux: auto
|
||||||
- name: Upload wheels
|
- name: Upload wheels
|
||||||
uses: actions/upload-artifact@v5.0.0
|
uses: actions/upload-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4 # v5.0.0
|
||||||
with:
|
with:
|
||||||
name: wheels-linux-${{ matrix.target }}
|
name: wheels-linux-${{ matrix.target }}
|
||||||
path: dist
|
path: dist
|
||||||
@@ -37,7 +37,7 @@ jobs:
|
|||||||
matrix:
|
matrix:
|
||||||
target: [x64, x86]
|
target: [x64, x86]
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v5.0.0
|
- uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v6.0.0
|
||||||
with:
|
with:
|
||||||
persist-credentials: false
|
persist-credentials: false
|
||||||
|
|
||||||
@@ -47,7 +47,7 @@ jobs:
|
|||||||
target: ${{ matrix.target }}
|
target: ${{ matrix.target }}
|
||||||
args: --release --out dist
|
args: --release --out dist
|
||||||
- name: Upload wheels
|
- name: Upload wheels
|
||||||
uses: actions/upload-artifact@v5.0.0
|
uses: actions/upload-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4 # v5.0.0
|
||||||
with:
|
with:
|
||||||
name: wheels-windows-${{ matrix.target }}
|
name: wheels-windows-${{ matrix.target }}
|
||||||
path: dist
|
path: dist
|
||||||
@@ -58,7 +58,7 @@ jobs:
|
|||||||
matrix:
|
matrix:
|
||||||
target: [x86_64, aarch64]
|
target: [x86_64, aarch64]
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v5.0.0
|
- uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v6.0.0
|
||||||
with:
|
with:
|
||||||
persist-credentials: false
|
persist-credentials: false
|
||||||
|
|
||||||
@@ -68,7 +68,7 @@ jobs:
|
|||||||
target: ${{ matrix.target }}
|
target: ${{ matrix.target }}
|
||||||
args: --release --out dist
|
args: --release --out dist
|
||||||
- name: Upload wheels
|
- name: Upload wheels
|
||||||
uses: actions/upload-artifact@v5.0.0
|
uses: actions/upload-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4 # v5.0.0
|
||||||
with:
|
with:
|
||||||
name: wheels-macos-${{ matrix.target }}
|
name: wheels-macos-${{ matrix.target }}
|
||||||
path: dist
|
path: dist
|
||||||
@@ -76,7 +76,7 @@ jobs:
|
|||||||
sdist:
|
sdist:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v5.0.0
|
- uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v6.0.0
|
||||||
with:
|
with:
|
||||||
persist-credentials: false
|
persist-credentials: false
|
||||||
|
|
||||||
@@ -86,7 +86,7 @@ jobs:
|
|||||||
command: sdist
|
command: sdist
|
||||||
args: --out dist
|
args: --out dist
|
||||||
- name: Upload sdist
|
- name: Upload sdist
|
||||||
uses: actions/upload-artifact@v5.0.0
|
uses: actions/upload-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4 # v5.0.0
|
||||||
with:
|
with:
|
||||||
name: wheels-sdist
|
name: wheels-sdist
|
||||||
path: dist
|
path: dist
|
||||||
@@ -103,10 +103,10 @@ jobs:
|
|||||||
# Used to generate artifact attestation
|
# Used to generate artifact attestation
|
||||||
attestations: write
|
attestations: write
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/download-artifact@v6.0.0
|
- uses: actions/download-artifact@018cc2cf5baa6db3ef3c5f8a56943fffe632ef53 # v6.0.0
|
||||||
|
|
||||||
- name: Generate artifact attestation
|
- name: Generate artifact attestation
|
||||||
uses: actions/attest-build-provenance@v3.0.0
|
uses: actions/attest-build-provenance@977bb373ede98d70efdf65b84cb5f73e068dcc2a # v3.0.0
|
||||||
with:
|
with:
|
||||||
subject-path: 'wheels-*/*'
|
subject-path: 'wheels-*/*'
|
||||||
|
|
||||||
|
|||||||
6
.github/workflows/scorecards.yml
vendored
6
.github/workflows/scorecards.yml
vendored
@@ -36,7 +36,7 @@ jobs:
|
|||||||
|
|
||||||
steps:
|
steps:
|
||||||
- name: "Checkout code"
|
- name: "Checkout code"
|
||||||
uses: actions/checkout@v5.0.0
|
uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v6.0.0
|
||||||
with:
|
with:
|
||||||
persist-credentials: false
|
persist-credentials: false
|
||||||
|
|
||||||
@@ -63,7 +63,7 @@ jobs:
|
|||||||
# Upload the results as artifacts (optional). Commenting out will disable uploads of run results in SARIF
|
# Upload the results as artifacts (optional). Commenting out will disable uploads of run results in SARIF
|
||||||
# format to the repository Actions tab.
|
# format to the repository Actions tab.
|
||||||
- name: "Upload artifact"
|
- name: "Upload artifact"
|
||||||
uses: actions/upload-artifact@v5.0.0
|
uses: actions/upload-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4 # v5.0.0
|
||||||
with:
|
with:
|
||||||
name: SARIF file
|
name: SARIF file
|
||||||
path: results.sarif
|
path: results.sarif
|
||||||
@@ -71,6 +71,6 @@ jobs:
|
|||||||
|
|
||||||
# Upload the results to GitHub's code scanning dashboard.
|
# Upload the results to GitHub's code scanning dashboard.
|
||||||
- name: "Upload to code-scanning"
|
- name: "Upload to code-scanning"
|
||||||
uses: github/codeql-action/upload-sarif@v4.31.2
|
uses: github/codeql-action/upload-sarif@e12f0178983d466f2f6028f5cc7a6d786fd97f4b # v4.31.4
|
||||||
with:
|
with:
|
||||||
sarif_file: results.sarif
|
sarif_file: results.sarif
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
repos:
|
repos:
|
||||||
- repo: https://github.com/gitleaks/gitleaks
|
- repo: https://github.com/gitleaks/gitleaks
|
||||||
rev: v8.28.0
|
rev: v8.29.0
|
||||||
hooks:
|
hooks:
|
||||||
- id: gitleaks
|
- id: gitleaks
|
||||||
|
|
||||||
@@ -16,7 +16,7 @@ repos:
|
|||||||
- id: trailing-whitespace
|
- id: trailing-whitespace
|
||||||
|
|
||||||
- repo: https://github.com/crate-ci/typos
|
- repo: https://github.com/crate-ci/typos
|
||||||
rev: v1.38.1
|
rev: v1.39.2
|
||||||
hooks:
|
hooks:
|
||||||
- id: typos
|
- id: typos
|
||||||
|
|
||||||
|
|||||||
67
CHANGELOG.md
67
CHANGELOG.md
@@ -7,6 +7,73 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|||||||
|
|
||||||
## [Unreleased]
|
## [Unreleased]
|
||||||
|
|
||||||
|
## [16.4.2](https://github.com/topgrade-rs/topgrade/compare/v16.4.1...v16.4.2) - 2025-11-20
|
||||||
|
|
||||||
|
### Other
|
||||||
|
|
||||||
|
- *(deps)* update dawidd6/action-homebrew-bump-formula action to v6 ([#1543](https://github.com/topgrade-rs/topgrade/pull/1543))
|
||||||
|
|
||||||
|
## [16.4.1](https://github.com/topgrade-rs/topgrade/compare/v16.4.0...v16.4.1) - 2025-11-20
|
||||||
|
|
||||||
|
### Other
|
||||||
|
|
||||||
|
- refactor run_containers error handling ([#1541](https://github.com/topgrade-rs/topgrade/pull/1541))
|
||||||
|
|
||||||
|
## [16.4.0](https://github.com/topgrade-rs/topgrade/compare/v16.3.0...v16.4.0) - 2025-11-20
|
||||||
|
|
||||||
|
### Added
|
||||||
|
|
||||||
|
- *(os)* add Origami Linux support ([#1530](https://github.com/topgrade-rs/topgrade/pull/1530))
|
||||||
|
- *(containers)* add option to run `system prune` ([#1523](https://github.com/topgrade-rs/topgrade/pull/1523))
|
||||||
|
|
||||||
|
### Fixed
|
||||||
|
|
||||||
|
- *(deps)* restore custom commands order ([#1535](https://github.com/topgrade-rs/topgrade/pull/1535))
|
||||||
|
|
||||||
|
### Other
|
||||||
|
|
||||||
|
- *(deps)* update clap, clap_builder, clap_complete ([#1540](https://github.com/topgrade-rs/topgrade/pull/1540))
|
||||||
|
- *(deps)* update github/codeql-action action to v4.31.4 ([#1531](https://github.com/topgrade-rs/topgrade/pull/1531))
|
||||||
|
- *(config)* add custom commands order test ([#1536](https://github.com/topgrade-rs/topgrade/pull/1536))
|
||||||
|
- make Config methods more consistent by utilizing `#[derive(Default)]` ([#1534](https://github.com/topgrade-rs/topgrade/pull/1534))
|
||||||
|
- *(issue templates)* use issue types ([#1533](https://github.com/topgrade-rs/topgrade/pull/1533))
|
||||||
|
- *(deps)* lock file maintenance ([#1505](https://github.com/topgrade-rs/topgrade/pull/1505))
|
||||||
|
- *(deps)* update actions/checkout digest to 93cb6ef ([#1526](https://github.com/topgrade-rs/topgrade/pull/1526))
|
||||||
|
- *(deps)* update actions/checkout action to v5.0.1 ([#1527](https://github.com/topgrade-rs/topgrade/pull/1527))
|
||||||
|
|
||||||
|
## [16.3.0](https://github.com/topgrade-rs/topgrade/compare/v16.2.1...v16.3.0) - 2025-11-16
|
||||||
|
|
||||||
|
### Added
|
||||||
|
|
||||||
|
- print summary and run post commands when (q)uit is used ([#1254](https://github.com/topgrade-rs/topgrade/pull/1254))
|
||||||
|
- run pre_sudo before pre_commands ([#1469](https://github.com/topgrade-rs/topgrade/pull/1469))
|
||||||
|
- *(chezmoi)* add `exclude_encrypted` config ([#1453](https://github.com/topgrade-rs/topgrade/pull/1453))
|
||||||
|
|
||||||
|
### Fixed
|
||||||
|
|
||||||
|
- *(elan)* skip running elan update on elan >=4.0.0 ([#1507](https://github.com/topgrade-rs/topgrade/pull/1507))
|
||||||
|
- *(deps)* Fix non-locked install on older version of Rust ([#1485](https://github.com/topgrade-rs/topgrade/pull/1485))
|
||||||
|
- *(deps)* Fix non-locked install on older version of Rust ([#1482](https://github.com/topgrade-rs/topgrade/pull/1482))
|
||||||
|
- *(bun)* skip self-update if not installed via official script ([#1476](https://github.com/topgrade-rs/topgrade/pull/1476))
|
||||||
|
- *(openbsd)* fix compilation on OpenBSD ([#1473](https://github.com/topgrade-rs/topgrade/pull/1473))
|
||||||
|
|
||||||
|
### Other
|
||||||
|
|
||||||
|
- *(license)* switch license variant to GPL-3.0-or-later ([#1518](https://github.com/topgrade-rs/topgrade/pull/1518))
|
||||||
|
- *(deps)* update some dependencies ([#1512](https://github.com/topgrade-rs/topgrade/pull/1512))
|
||||||
|
- *(deps)* update github/codeql-action action to v4.31.3 ([#1483](https://github.com/topgrade-rs/topgrade/pull/1483))
|
||||||
|
- remove unnecessary cfg-if dependency ([#1509](https://github.com/topgrade-rs/topgrade/pull/1509))
|
||||||
|
- *(lint_pr)* run on synchronize, and add zizmor ignore ([#1508](https://github.com/topgrade-rs/topgrade/pull/1508))
|
||||||
|
- *(pre-commit)* autoupdate ([#1464](https://github.com/topgrade-rs/topgrade/pull/1464))
|
||||||
|
- improve issue templates ([#1235](https://github.com/topgrade-rs/topgrade/pull/1235))
|
||||||
|
- *(deps)* bump mac-notification-sys, use main branch temporarily ([#1506](https://github.com/topgrade-rs/topgrade/pull/1506))
|
||||||
|
- *(deps)* lock file maintenance ([#1481](https://github.com/topgrade-rs/topgrade/pull/1481))
|
||||||
|
- *(deps)* pin dependencies ([#1478](https://github.com/topgrade-rs/topgrade/pull/1478))
|
||||||
|
- *(deps)* update actions/dependency-review-action action to v4.8.2 ([#1479](https://github.com/topgrade-rs/topgrade/pull/1479))
|
||||||
|
- Add Renovate ([#1477](https://github.com/topgrade-rs/topgrade/pull/1477))
|
||||||
|
- Replace main's self update with a proper step call ([#1470](https://github.com/topgrade-rs/topgrade/pull/1470))
|
||||||
|
- *(release)* Fix homebrew releases ([#1468](https://github.com/topgrade-rs/topgrade/pull/1468))
|
||||||
|
|
||||||
## [16.2.1](https://github.com/topgrade-rs/topgrade/compare/v16.2.0...v16.2.1) - 2025-11-10
|
## [16.2.1](https://github.com/topgrade-rs/topgrade/compare/v16.2.0...v16.2.1) - 2025-11-10
|
||||||
|
|
||||||
### Fixed
|
### Fixed
|
||||||
|
|||||||
2251
Cargo.lock
generated
2251
Cargo.lock
generated
File diff suppressed because it is too large
Load Diff
40
Cargo.toml
40
Cargo.toml
@@ -3,37 +3,35 @@ name = "topgrade"
|
|||||||
description = "Upgrade all the things"
|
description = "Upgrade all the things"
|
||||||
categories = ["os"]
|
categories = ["os"]
|
||||||
keywords = ["upgrade", "update"]
|
keywords = ["upgrade", "update"]
|
||||||
license = "GPL-3.0"
|
license = "GPL-3.0-or-later"
|
||||||
repository = "https://github.com/topgrade-rs/topgrade"
|
repository = "https://github.com/topgrade-rs/topgrade"
|
||||||
rust-version = "1.84.1"
|
rust-version = "1.87.0"
|
||||||
version = "16.2.1"
|
version = "16.4.2"
|
||||||
authors = ["Roey Darwish Dror <roey.ghost@gmail.com>", "Thomas Schönauer <t.schoenauer@hgs-wt.at>"]
|
authors = ["Roey Darwish Dror <roey.ghost@gmail.com>", "Thomas Schönauer <t.schoenauer@hgs-wt.at>"]
|
||||||
exclude = ["doc/screenshot.gif", "BREAKINGCHANGES_dev.md"]
|
exclude = ["doc/screenshot.gif", "BREAKINGCHANGES_dev.md"]
|
||||||
edition = "2021"
|
edition = "2024"
|
||||||
|
|
||||||
readme = "README.md"
|
readme = "README.md"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
home = "~0.5"
|
etcetera = "~0.11.0"
|
||||||
etcetera = "~0.8"
|
|
||||||
serde = { version = "~1.0", features = ["derive"] }
|
serde = { version = "~1.0", features = ["derive"] }
|
||||||
toml = "0.8"
|
toml = { version = "~0.9.8", features = ["preserve_order"] }
|
||||||
which_crate = { version = "~6.0", package = "which" }
|
which_crate = { version = "~8.0", package = "which" }
|
||||||
shellexpand = "~3.1"
|
shellexpand = "~3.1"
|
||||||
clap = { version = "~4.5", features = ["cargo", "derive"] }
|
clap = { version = "~4.5", features = ["cargo", "derive"] }
|
||||||
clap_complete = "~4.5"
|
clap_complete = "~4.5"
|
||||||
clap_mangen = "~0.2"
|
clap_mangen = "~0.2"
|
||||||
walkdir = "~2.5"
|
walkdir = "~2.5"
|
||||||
console = "~0.15"
|
console = "~0.16"
|
||||||
chrono = "~0.4"
|
chrono = "~0.4"
|
||||||
glob = "~0.3"
|
glob = "~0.3"
|
||||||
strum = { version = "~0.26", features = ["derive"] }
|
strum = { version = "~0.27", features = ["derive"] }
|
||||||
thiserror = "~1.0"
|
thiserror = "~2.0"
|
||||||
tempfile = "~3.10"
|
tempfile = "~3.23"
|
||||||
cfg-if = "~1.0"
|
tokio = { version = "~1.48", 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.12"
|
||||||
semver = "~1.0"
|
semver = "~1.0"
|
||||||
shell-words = "~1.1"
|
shell-words = "~1.1"
|
||||||
color-eyre = "~0.6"
|
color-eyre = "~0.6"
|
||||||
@@ -48,6 +46,10 @@ sys-locale = "0.3.1"
|
|||||||
jetbrains-toolbox-updater = "5.0.0"
|
jetbrains-toolbox-updater = "5.0.0"
|
||||||
indexmap = { version = "2.9.0", features = ["serde"] }
|
indexmap = { version = "2.9.0", features = ["serde"] }
|
||||||
serde_json = "1.0.145"
|
serde_json = "1.0.145"
|
||||||
|
clap-cargo = "0.18.0"
|
||||||
|
|
||||||
|
[patch.crates-io]
|
||||||
|
mac-notification-sys = { git = "https://github.com/h4llow3En/mac-notification-sys" }
|
||||||
|
|
||||||
[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" }]
|
||||||
@@ -58,7 +60,7 @@ git = "*"
|
|||||||
[package.metadata.deb]
|
[package.metadata.deb]
|
||||||
name = "topgrade"
|
name = "topgrade"
|
||||||
maintainer = "Chris Gelatt <kreeblah@gmail.com>"
|
maintainer = "Chris Gelatt <kreeblah@gmail.com>"
|
||||||
copyright = "2024, Topgrade Team"
|
copyright = "2025, Topgrade Team"
|
||||||
license-file = ["LICENSE", "0"]
|
license-file = ["LICENSE", "0"]
|
||||||
depends = "$auto"
|
depends = "$auto"
|
||||||
extended-description = "Keeping your system up to date usually involves invoking multiple package managers. This results in big, non-portable shell one-liners saved in your shell. To remedy this, Topgrade detects which tools you use and runs the appropriate commands to update them."
|
extended-description = "Keeping your system up to date usually involves invoking multiple package managers. This results in big, non-portable shell one-liners saved in your shell. To remedy this, Topgrade detects which tools you use and runs the appropriate commands to update them."
|
||||||
@@ -77,14 +79,14 @@ assets = [
|
|||||||
]
|
]
|
||||||
|
|
||||||
[target.'cfg(unix)'.dependencies]
|
[target.'cfg(unix)'.dependencies]
|
||||||
nix = { version = "~0.29", features = ["hostname", "signal", "user"] }
|
nix = { version = "~0.30", features = ["hostname", "signal", "user"] }
|
||||||
rust-ini = "~0.21"
|
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.42", default-features = false, optional = true, package = "self_update", features = ["archive-tar", "compression-flate2", "rustls"] }
|
||||||
|
|
||||||
[target.'cfg(windows)'.dependencies]
|
[target.'cfg(windows)'.dependencies]
|
||||||
is_elevated = "~0.1"
|
is_elevated = "~0.1"
|
||||||
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"] }
|
self_update_crate = { version = "~0.42", default-features = false, optional = true, package = "self_update", features = ["archive-zip", "compression-zip-deflate", "rustls"] }
|
||||||
windows = { version = "~0.62", features = ["Win32_System_Console"] }
|
windows = { version = "~0.62", features = ["Win32_System_Console"] }
|
||||||
windows-registry = "~0.6"
|
windows-registry = "~0.6"
|
||||||
|
|
||||||
|
|||||||
@@ -37,6 +37,8 @@ To remedy this, **Topgrade** detects which tools you use and runs the appropriat
|
|||||||
- Windows ([Winget](https://learn.microsoft.com/en-us/windows/package-manager/winget/)): [
|
- Windows ([Winget](https://learn.microsoft.com/en-us/windows/package-manager/winget/)): [
|
||||||
`winget install --id=topgrade-rs.topgrade -e`](https://winstall.app/apps/topgrade-rs.topgrade)
|
`winget install --id=topgrade-rs.topgrade -e`](https://winstall.app/apps/topgrade-rs.topgrade)
|
||||||
- macOS or Linux ([Homebrew](https://brew.sh/)): [`brew install topgrade`](https://formulae.brew.sh/formula/topgrade)
|
- macOS or Linux ([Homebrew](https://brew.sh/)): [`brew install topgrade`](https://formulae.brew.sh/formula/topgrade)
|
||||||
|
- Fedora/RHEL/AlmaLinux/CentOS-Stream ([Copr](https://copr.fedorainfracloud.org/)): [
|
||||||
|
`sudo dnf copr enable lilay/topgrade && sudo dnf install topgrade`](https://copr.fedorainfracloud.org/coprs/lilay/topgrade/)
|
||||||
|
|
||||||
### Community-maintained
|
### Community-maintained
|
||||||
|
|
||||||
@@ -46,8 +48,6 @@ To remedy this, **Topgrade** detects which tools you use and runs the appropriat
|
|||||||
`scoop bucket add main && scoop install main/topgrade`](https://scoop.sh/#/apps?q=topgrade)
|
`scoop bucket add main && scoop install main/topgrade`](https://scoop.sh/#/apps?q=topgrade)
|
||||||
- macOS ([MacPorts](https://www.macports.org/)): [
|
- macOS ([MacPorts](https://www.macports.org/)): [
|
||||||
`sudo port install topgrade`](https://ports.macports.org/port/topgrade/)
|
`sudo port install topgrade`](https://ports.macports.org/port/topgrade/)
|
||||||
- Fedora ([Copr](https://copr.fedorainfracloud.org/)): [
|
|
||||||
`dnf copr enable lilay/topgrade && dnf install topgrade`](https://copr.fedorainfracloud.org/coprs/lilay/topgrade/)
|
|
||||||
- NixOS or Nix (nixpkgs): [topgrade](https://search.nixos.org/packages?show=topgrade)
|
- NixOS or Nix (nixpkgs): [topgrade](https://search.nixos.org/packages?show=topgrade)
|
||||||
- Void Linux: [`sudo xbps-install -S topgrade`](https://voidlinux.org/packages/?arch=x86_64&q=topgrade)
|
- Void Linux: [`sudo xbps-install -S topgrade`](https://voidlinux.org/packages/?arch=x86_64&q=topgrade)
|
||||||
|
|
||||||
|
|||||||
@@ -286,6 +286,25 @@
|
|||||||
# winget_use_sudo = true
|
# winget_use_sudo = true
|
||||||
|
|
||||||
|
|
||||||
|
[chezmoi]
|
||||||
|
# Exclude encrypted files from update
|
||||||
|
# (default: false)
|
||||||
|
# exclude_encrypted = false
|
||||||
|
|
||||||
|
[mise]
|
||||||
|
# Upgrades to the latest version available, bumping the version in mise.toml
|
||||||
|
# (default: false)
|
||||||
|
# bump = false
|
||||||
|
|
||||||
|
# Number of jobs to run in parallel
|
||||||
|
# (default: 4)
|
||||||
|
# jobs = 4
|
||||||
|
|
||||||
|
# Run interactively
|
||||||
|
# (default: false)
|
||||||
|
# interactive = false
|
||||||
|
|
||||||
|
|
||||||
[npm]
|
[npm]
|
||||||
# Use sudo if the NPM directory isn't owned by the current user
|
# Use sudo if the NPM directory isn't owned by the current user
|
||||||
# use_sudo = true
|
# use_sudo = true
|
||||||
@@ -337,6 +356,10 @@
|
|||||||
# Specify the runtime to use for containers (default: "docker", allowed values: "docker", "podman")
|
# Specify the runtime to use for containers (default: "docker", allowed values: "docker", "podman")
|
||||||
# runtime = "podman"
|
# runtime = "podman"
|
||||||
|
|
||||||
|
# Run 'docker system prune' to clean up unused containers, networks, and build cache
|
||||||
|
# (default: false)
|
||||||
|
# system_prune = false
|
||||||
|
|
||||||
[lensfun]
|
[lensfun]
|
||||||
# If disabled, Topgrade invokes `lensfun‑update‑data` without root privilege,
|
# 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,
|
||||||
|
|||||||
@@ -694,6 +694,14 @@ _version: 2
|
|||||||
zh_CN: "不是专用的 macOS brew"
|
zh_CN: "不是专用的 macOS brew"
|
||||||
zh_TW: "不是專門的 macOS brew"
|
zh_TW: "不是專門的 macOS brew"
|
||||||
de: "Kein angepasstes Brew für macOS"
|
de: "Kein angepasstes Brew für macOS"
|
||||||
|
"Homebrew cask support on Linux requires Homebrew 4.5.0 or later (found {version})":
|
||||||
|
en: "Homebrew cask support on Linux requires Homebrew 4.5.0 or later (found %{version})"
|
||||||
|
lt: "Homebrew cask palaikymas Linux sistemoje reikalauja Homebrew 4.5.0 arba naujesnes versijos (rasta %{version})"
|
||||||
|
es: "El soporte de cask de Homebrew en Linux requiere Homebrew 4.5.0 o posterior (encontrado %{version})"
|
||||||
|
fr: "Le support de cask Homebrew sur Linux nécessite Homebrew 4.5.0 ou supérieur (trouvé %{version})"
|
||||||
|
zh_CN: "Linux 上的 Homebrew cask 支持需要 Homebrew 4.5.0 或更高版本(找到 %{version})"
|
||||||
|
zh_TW: "Linux 上的 Homebrew cask 支援需要 Homebrew 4.5.0 或更高版本(找到 %{version})"
|
||||||
|
de: "Homebrew-Cask-Unterstützung unter Linux erfordert Homebrew 4.5.0 oder höher (gefunden %{version})"
|
||||||
"Guix Pull Failed, Skipping":
|
"Guix Pull Failed, Skipping":
|
||||||
en: "Guix Pull Failed, Skipping"
|
en: "Guix Pull Failed, Skipping"
|
||||||
lt: "Guix traukti nepavyko, praleidžiama"
|
lt: "Guix traukti nepavyko, praleidžiama"
|
||||||
@@ -1306,14 +1314,6 @@ _version: 2
|
|||||||
zh_CN: "Windows 更新"
|
zh_CN: "Windows 更新"
|
||||||
zh_TW: "Windows 更新"
|
zh_TW: "Windows 更新"
|
||||||
de: "Windows-Update"
|
de: "Windows-Update"
|
||||||
"Checking if /etc/motd contains -current or -beta":
|
|
||||||
en: "Checking if /etc/motd contains -current or -beta"
|
|
||||||
lt: "Tikrinimas, jei /etc/motd yra -current arba -beta"
|
|
||||||
es: "Comprobación de si /etc/motd contiene -current o -beta"
|
|
||||||
fr: "Vérification si /etc/motd contient -current ou -beta"
|
|
||||||
zh_CN: "检查 /etc/motd 是否包含 -current 或 -beta"
|
|
||||||
zh_TW: "檢查 /etc/motd 是否包含 -current 或 -beta"
|
|
||||||
de: "Überprüfen, ob /etc/motd -current oder -beta enthält"
|
|
||||||
"Microsoft Store":
|
"Microsoft Store":
|
||||||
en: "Microsoft Store"
|
en: "Microsoft Store"
|
||||||
lt: "Microsoft parduotuvė"
|
lt: "Microsoft parduotuvė"
|
||||||
|
|||||||
@@ -5,13 +5,20 @@ build-backend = "maturin"
|
|||||||
[project]
|
[project]
|
||||||
name = "topgrade"
|
name = "topgrade"
|
||||||
dynamic = ["version"]
|
dynamic = ["version"]
|
||||||
|
description = "Upgrade all the things"
|
||||||
|
readme = "README.md"
|
||||||
|
license = "GPL-3.0-or-later"
|
||||||
requires-python = ">=3.7"
|
requires-python = ">=3.7"
|
||||||
classifiers = [
|
classifiers = [
|
||||||
|
"License :: OSI Approved :: GNU General Public License v3 (GPLv3)",
|
||||||
"Programming Language :: Rust",
|
"Programming Language :: Rust",
|
||||||
"Programming Language :: Python :: Implementation :: CPython",
|
"Programming Language :: Python :: Implementation :: CPython",
|
||||||
"Programming Language :: Python :: Implementation :: PyPy",
|
"Programming Language :: Python :: Implementation :: PyPy",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
urls.bugs = "https://github.com/topgrade-rs/topgrade/issues"
|
||||||
|
urls.homepage = "https://github.com/topgrade-rs/topgrade"
|
||||||
|
|
||||||
|
|
||||||
[tool.maturin]
|
[tool.maturin]
|
||||||
bindings = "bin"
|
bindings = "bin"
|
||||||
|
|||||||
10
renovate.json
Normal file
10
renovate.json
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
{
|
||||||
|
"$schema": "https://docs.renovatebot.com/renovate-schema.json",
|
||||||
|
"extends": [
|
||||||
|
"config:best-practices",
|
||||||
|
":semanticCommits"
|
||||||
|
],
|
||||||
|
"lockFileMaintenance": {
|
||||||
|
"enabled": true
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,2 +1,2 @@
|
|||||||
[toolchain]
|
[toolchain]
|
||||||
channel = "1.84.1"
|
channel = "1.87.0"
|
||||||
|
|||||||
@@ -4,17 +4,17 @@
|
|||||||
//! 1. The Topgrade being executed is a new major release
|
//! 1. The Topgrade being executed is a new major release
|
||||||
//! 2. This is the first launch of that major release
|
//! 2. This is the first launch of that major release
|
||||||
|
|
||||||
use crate::terminal::print_separator;
|
|
||||||
#[cfg(windows)]
|
#[cfg(windows)]
|
||||||
use crate::WINDOWS_DIRS;
|
use crate::WINDOWS_DIRS;
|
||||||
#[cfg(unix)]
|
#[cfg(unix)]
|
||||||
use crate::XDG_DIRS;
|
use crate::XDG_DIRS;
|
||||||
|
use crate::terminal::print_separator;
|
||||||
use color_eyre::eyre::Result;
|
use color_eyre::eyre::Result;
|
||||||
use etcetera::base_strategy::BaseStrategy;
|
use etcetera::base_strategy::BaseStrategy;
|
||||||
use rust_i18n::t;
|
use rust_i18n::t;
|
||||||
use std::{
|
use std::{
|
||||||
env::var,
|
env::var,
|
||||||
fs::{read_to_string, OpenOptions},
|
fs::{OpenOptions, read_to_string},
|
||||||
io::Write,
|
io::Write,
|
||||||
path::PathBuf,
|
path::PathBuf,
|
||||||
str::FromStr,
|
str::FromStr,
|
||||||
|
|||||||
@@ -5,8 +5,8 @@ use std::process::Child;
|
|||||||
use std::process::{Command, ExitStatus, Output};
|
use std::process::{Command, ExitStatus, Output};
|
||||||
|
|
||||||
use color_eyre::eyre;
|
use color_eyre::eyre;
|
||||||
use color_eyre::eyre::eyre;
|
|
||||||
use color_eyre::eyre::Context;
|
use color_eyre::eyre::Context;
|
||||||
|
use color_eyre::eyre::eyre;
|
||||||
|
|
||||||
use crate::error::TopgradeError;
|
use crate::error::TopgradeError;
|
||||||
|
|
||||||
|
|||||||
104
src/config.rs
104
src/config.rs
@@ -1,6 +1,6 @@
|
|||||||
#![allow(dead_code)]
|
#![allow(dead_code)]
|
||||||
|
|
||||||
use std::fs::{write, File};
|
use std::fs::{File, write};
|
||||||
use std::io::Write;
|
use std::io::Write;
|
||||||
use std::path::{Path, PathBuf};
|
use std::path::{Path, PathBuf};
|
||||||
use std::process::Command;
|
use std::process::Command;
|
||||||
@@ -60,6 +60,7 @@ pub struct Containers {
|
|||||||
#[merge(strategy = crate::utils::merge_strategies::vec_prepend_opt)]
|
#[merge(strategy = crate::utils::merge_strategies::vec_prepend_opt)]
|
||||||
ignored_containers: Option<Vec<String>>,
|
ignored_containers: Option<Vec<String>>,
|
||||||
runtime: Option<ContainerRuntime>,
|
runtime: Option<ContainerRuntime>,
|
||||||
|
system_prune: Option<bool>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Deserialize, Default, Debug, Merge)]
|
#[derive(Deserialize, Default, Debug, Merge)]
|
||||||
@@ -165,6 +166,22 @@ pub struct Deno {
|
|||||||
version: Option<String>,
|
version: Option<String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Deserialize, Default, Debug, Merge)]
|
||||||
|
#[serde(deny_unknown_fields)]
|
||||||
|
#[allow(clippy::upper_case_acronyms)]
|
||||||
|
pub struct Chezmoi {
|
||||||
|
exclude_encrypted: Option<bool>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Deserialize, Default, Debug, Merge)]
|
||||||
|
#[serde(deny_unknown_fields)]
|
||||||
|
#[allow(clippy::upper_case_acronyms)]
|
||||||
|
pub struct Mise {
|
||||||
|
bump: Option<bool>,
|
||||||
|
interactive: Option<bool>,
|
||||||
|
jobs: Option<u32>,
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Deserialize, Default, Debug, Merge)]
|
#[derive(Deserialize, Default, Debug, Merge)]
|
||||||
#[serde(deny_unknown_fields)]
|
#[serde(deny_unknown_fields)]
|
||||||
#[allow(clippy::upper_case_acronyms)]
|
#[allow(clippy::upper_case_acronyms)]
|
||||||
@@ -196,9 +213,10 @@ pub struct Brew {
|
|||||||
fetch_head: Option<bool>,
|
fetch_head: Option<bool>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Deserialize, Clone, Copy)]
|
#[derive(Debug, Deserialize, Clone, Copy, Default)]
|
||||||
#[serde(rename_all = "snake_case")]
|
#[serde(rename_all = "snake_case")]
|
||||||
pub enum ArchPackageManager {
|
pub enum ArchPackageManager {
|
||||||
|
#[default]
|
||||||
Autodetect,
|
Autodetect,
|
||||||
Aura,
|
Aura,
|
||||||
GarudaUpdate,
|
GarudaUpdate,
|
||||||
@@ -210,9 +228,10 @@ pub enum ArchPackageManager {
|
|||||||
Yay,
|
Yay,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Copy, Debug, Deserialize)]
|
#[derive(Clone, Copy, Debug, Deserialize, Default)]
|
||||||
#[serde(rename_all = "snake_case")]
|
#[serde(rename_all = "snake_case")]
|
||||||
pub enum ContainerRuntime {
|
pub enum ContainerRuntime {
|
||||||
|
#[default] // defaults to a popular choice
|
||||||
Docker,
|
Docker,
|
||||||
Podman,
|
Podman,
|
||||||
}
|
}
|
||||||
@@ -350,10 +369,11 @@ pub struct Misc {
|
|||||||
show_distribution_summary: Option<bool>,
|
show_distribution_summary: Option<bool>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Copy, Debug, Deserialize, ValueEnum)]
|
#[derive(Clone, Copy, Debug, Deserialize, ValueEnum, Default)]
|
||||||
#[clap(rename_all = "snake_case")]
|
#[clap(rename_all = "snake_case")]
|
||||||
#[serde(rename_all = "snake_case")]
|
#[serde(rename_all = "snake_case")]
|
||||||
pub enum TmuxSessionMode {
|
pub enum TmuxSessionMode {
|
||||||
|
#[default]
|
||||||
AttachIfNotInSession,
|
AttachIfNotInSession,
|
||||||
AttachAlways,
|
AttachAlways,
|
||||||
}
|
}
|
||||||
@@ -457,6 +477,12 @@ pub struct ConfigFile {
|
|||||||
#[merge(strategy = crate::utils::merge_strategies::inner_merge_opt)]
|
#[merge(strategy = crate::utils::merge_strategies::inner_merge_opt)]
|
||||||
npm: Option<NPM>,
|
npm: Option<NPM>,
|
||||||
|
|
||||||
|
#[merge(strategy = crate::utils::merge_strategies::inner_merge_opt)]
|
||||||
|
chezmoi: Option<Chezmoi>,
|
||||||
|
|
||||||
|
#[merge(strategy = crate::utils::merge_strategies::inner_merge_opt)]
|
||||||
|
mise: Option<Mise>,
|
||||||
|
|
||||||
#[merge(strategy = crate::utils::merge_strategies::inner_merge_opt)]
|
#[merge(strategy = crate::utils::merge_strategies::inner_merge_opt)]
|
||||||
yarn: Option<Yarn>,
|
yarn: Option<Yarn>,
|
||||||
|
|
||||||
@@ -703,7 +729,7 @@ impl ConfigFile {
|
|||||||
// TODO: i18n of clap currently not easily possible. Waiting for https://github.com/clap-rs/clap/issues/380
|
// TODO: i18n of clap currently not easily possible. Waiting for https://github.com/clap-rs/clap/issues/380
|
||||||
// Tracking issue for i18n: https://github.com/topgrade-rs/topgrade/issues/859
|
// Tracking issue for i18n: https://github.com/topgrade-rs/topgrade/issues/859
|
||||||
#[derive(Parser, Debug)]
|
#[derive(Parser, Debug)]
|
||||||
#[command(name = "topgrade", version)]
|
#[command(name = "topgrade", version, styles = clap_cargo::style::CLAP_STYLING)]
|
||||||
pub struct CommandLineArgs {
|
pub struct CommandLineArgs {
|
||||||
/// Edit the configuration file
|
/// Edit the configuration file
|
||||||
#[arg(long = "edit-config")]
|
#[arg(long = "edit-config")]
|
||||||
@@ -945,7 +971,16 @@ impl Config {
|
|||||||
.containers
|
.containers
|
||||||
.as_ref()
|
.as_ref()
|
||||||
.and_then(|containers| containers.runtime)
|
.and_then(|containers| containers.runtime)
|
||||||
.unwrap_or(ContainerRuntime::Docker) // defaults to a popular choice
|
.unwrap_or_default()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Whether to run system prune for containers.
|
||||||
|
pub fn containers_system_prune(&self) -> bool {
|
||||||
|
self.config_file
|
||||||
|
.containers
|
||||||
|
.as_ref()
|
||||||
|
.and_then(|containers| containers.system_prune)
|
||||||
|
.unwrap_or(false)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Tell whether the specified step should run.
|
/// Tell whether the specified step should run.
|
||||||
@@ -1017,7 +1052,7 @@ impl Config {
|
|||||||
.misc
|
.misc
|
||||||
.as_ref()
|
.as_ref()
|
||||||
.and_then(|misc| misc.tmux_session_mode)
|
.and_then(|misc| misc.tmux_session_mode)
|
||||||
.unwrap_or(TmuxSessionMode::AttachIfNotInSession)
|
.unwrap_or_default()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Tell whether we should perform cleanup steps.
|
/// Tell whether we should perform cleanup steps.
|
||||||
@@ -1271,7 +1306,7 @@ impl Config {
|
|||||||
.vim
|
.vim
|
||||||
.as_ref()
|
.as_ref()
|
||||||
.and_then(|c| c.force_plug_update)
|
.and_then(|c| c.force_plug_update)
|
||||||
.unwrap_or_default()
|
.unwrap_or(false)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Whether to send a desktop notification at the beginning of every step
|
/// Whether to send a desktop notification at the beginning of every step
|
||||||
@@ -1344,7 +1379,7 @@ impl Config {
|
|||||||
.linux
|
.linux
|
||||||
.as_ref()
|
.as_ref()
|
||||||
.and_then(|s| s.arch_package_manager)
|
.and_then(|s| s.arch_package_manager)
|
||||||
.unwrap_or(ArchPackageManager::Autodetect)
|
.unwrap_or_default()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Extra yay arguments
|
/// Extra yay arguments
|
||||||
@@ -1597,8 +1632,7 @@ impl Config {
|
|||||||
self.config_file.misc.as_ref().and_then(|misc| misc.sudo_command)
|
self.config_file.misc.as_ref().and_then(|misc| misc.sudo_command)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// If `true`, `sudo` should be called after `pre_commands` in order to elevate at the
|
/// If `true`, `sudo -v` should be called to cache credentials at the start of the run
|
||||||
/// start of the session (and not in the middle).
|
|
||||||
pub fn pre_sudo(&self) -> bool {
|
pub fn pre_sudo(&self) -> bool {
|
||||||
self.config_file
|
self.config_file
|
||||||
.misc
|
.misc
|
||||||
@@ -1774,6 +1808,34 @@ impl Config {
|
|||||||
.unwrap_or(false)
|
.unwrap_or(false)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn chezmoi_exclude_encrypted(&self) -> bool {
|
||||||
|
self.config_file
|
||||||
|
.chezmoi
|
||||||
|
.as_ref()
|
||||||
|
.and_then(|chezmoi| chezmoi.exclude_encrypted)
|
||||||
|
.unwrap_or(false)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn mise_bump(&self) -> bool {
|
||||||
|
self.config_file
|
||||||
|
.mise
|
||||||
|
.as_ref()
|
||||||
|
.and_then(|mise| mise.bump)
|
||||||
|
.unwrap_or(false)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn mise_jobs(&self) -> u32 {
|
||||||
|
self.config_file.mise.as_ref().and_then(|mise| mise.jobs).unwrap_or(4)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn mise_interactive(&self) -> bool {
|
||||||
|
self.config_file
|
||||||
|
.mise
|
||||||
|
.as_ref()
|
||||||
|
.and_then(|mise| mise.interactive)
|
||||||
|
.unwrap_or(false)
|
||||||
|
}
|
||||||
|
|
||||||
pub fn vscode_profile(&self) -> Option<&str> {
|
pub fn vscode_profile(&self) -> Option<&str> {
|
||||||
let vscode_cfg = self.config_file.vscode.as_ref()?;
|
let vscode_cfg = self.config_file.vscode.as_ref()?;
|
||||||
let profile = vscode_cfg.profile.as_ref()?;
|
let profile = vscode_cfg.profile.as_ref()?;
|
||||||
@@ -1862,4 +1924,24 @@ mod test {
|
|||||||
config.opt = CommandLineArgs::parse_from(["topgrade", "--remote-host-limit", "other_hostname"]);
|
config.opt = CommandLineArgs::parse_from(["topgrade", "--remote-host-limit", "other_hostname"]);
|
||||||
assert!(!config.should_execute_remote(Ok("hostname".to_string()), "user@remote_hostname"));
|
assert!(!config.should_execute_remote(Ok("hostname".to_string()), "user@remote_hostname"));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Ensure that custom commands are stored in insertion order.
|
||||||
|
#[test]
|
||||||
|
fn test_custom_commands_order() {
|
||||||
|
let toml_str = r#"
|
||||||
|
[commands]
|
||||||
|
z = "cmd_z"
|
||||||
|
y = "cmd_y"
|
||||||
|
x = "cmd_x"
|
||||||
|
"#;
|
||||||
|
let order: Vec<_> = toml::from_str::<ConfigFile>(toml_str)
|
||||||
|
.expect("toml parse error")
|
||||||
|
.commands
|
||||||
|
.expect("commands field missing")
|
||||||
|
.keys()
|
||||||
|
.cloned()
|
||||||
|
.collect();
|
||||||
|
|
||||||
|
assert_eq!(order, vec!["z", "y", "x"]);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
//! SIGINT handling in Unix systems.
|
//! SIGINT handling in Unix systems.
|
||||||
use crate::ctrlc::interrupted::set_interrupted;
|
use crate::ctrlc::interrupted::set_interrupted;
|
||||||
use nix::sys::signal::{sigaction, SaFlags, SigAction, SigHandler, SigSet, Signal};
|
use nix::sys::signal::{SaFlags, SigAction, SigHandler, SigSet, Signal, sigaction};
|
||||||
|
|
||||||
/// Handle SIGINT. Set the interruption flag.
|
/// Handle SIGINT. Set the interruption flag.
|
||||||
extern "C" fn handle_sigint(_: i32) {
|
extern "C" fn handle_sigint(_: i32) {
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
//! A stub for Ctrl + C handling.
|
//! A stub for Ctrl + C handling.
|
||||||
use crate::ctrlc::interrupted::set_interrupted;
|
use crate::ctrlc::interrupted::set_interrupted;
|
||||||
use tracing::error;
|
use tracing::error;
|
||||||
|
use windows::Win32::System::Console::{CTRL_C_EVENT, SetConsoleCtrlHandler};
|
||||||
use windows::core::BOOL;
|
use windows::core::BOOL;
|
||||||
use windows::Win32::System::Console::{SetConsoleCtrlHandler, CTRL_C_EVENT};
|
|
||||||
|
|
||||||
extern "system" fn handler(ctrl_type: u32) -> BOOL {
|
extern "system" fn handler(ctrl_type: u32) -> BOOL {
|
||||||
match ctrl_type {
|
match ctrl_type {
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ use std::process::{Child, Command, ExitStatus, Output};
|
|||||||
|
|
||||||
use color_eyre::eyre::Result;
|
use color_eyre::eyre::Result;
|
||||||
use rust_i18n::t;
|
use rust_i18n::t;
|
||||||
use tracing::{debug, enabled, Level};
|
use tracing::{Level, debug, enabled};
|
||||||
|
|
||||||
use crate::command::CommandExt;
|
use crate::command::CommandExt;
|
||||||
use crate::error::DryRun;
|
use crate::error::DryRun;
|
||||||
|
|||||||
52
src/main.rs
52
src/main.rs
@@ -1,6 +1,7 @@
|
|||||||
#![allow(clippy::cognitive_complexity)]
|
#![allow(clippy::cognitive_complexity)]
|
||||||
|
|
||||||
use std::env;
|
use std::env;
|
||||||
|
use std::env::home_dir;
|
||||||
use std::io;
|
use std::io;
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
use std::process::exit;
|
use std::process::exit;
|
||||||
@@ -8,11 +9,10 @@ use std::time::Duration;
|
|||||||
|
|
||||||
use crate::breaking_changes::{first_run_of_major_release, print_breaking_changes, should_skip, write_keep_file};
|
use crate::breaking_changes::{first_run_of_major_release, print_breaking_changes, should_skip, write_keep_file};
|
||||||
use clap::CommandFactory;
|
use clap::CommandFactory;
|
||||||
use clap::{crate_version, Parser};
|
use clap::{Parser, crate_version};
|
||||||
use color_eyre::eyre::Context;
|
use color_eyre::eyre::Context;
|
||||||
use color_eyre::eyre::Result;
|
use color_eyre::eyre::Result;
|
||||||
use console::Key;
|
use console::Key;
|
||||||
use etcetera::base_strategy::BaseStrategy;
|
|
||||||
#[cfg(windows)]
|
#[cfg(windows)]
|
||||||
use etcetera::base_strategy::Windows;
|
use etcetera::base_strategy::Windows;
|
||||||
#[cfg(unix)]
|
#[cfg(unix)]
|
||||||
@@ -49,7 +49,7 @@ mod sudo;
|
|||||||
mod terminal;
|
mod terminal;
|
||||||
mod utils;
|
mod utils;
|
||||||
|
|
||||||
pub(crate) static HOME_DIR: LazyLock<PathBuf> = LazyLock::new(|| home::home_dir().expect("No home directory"));
|
pub(crate) static HOME_DIR: LazyLock<PathBuf> = LazyLock::new(|| home_dir().expect("No home directory"));
|
||||||
#[cfg(unix)]
|
#[cfg(unix)]
|
||||||
pub(crate) static XDG_DIRS: LazyLock<Xdg> = LazyLock::new(|| Xdg::new().expect("No home directory"));
|
pub(crate) static XDG_DIRS: LazyLock<Xdg> = LazyLock::new(|| Xdg::new().expect("No home directory"));
|
||||||
|
|
||||||
@@ -99,7 +99,7 @@ fn run() -> Result<()> {
|
|||||||
let mut parts = env.split('=');
|
let mut parts = env.split('=');
|
||||||
let var = parts.next().unwrap();
|
let var = parts.next().unwrap();
|
||||||
let value = parts.next().unwrap();
|
let value = parts.next().unwrap();
|
||||||
env::set_var(var, value);
|
unsafe { env::set_var(var, value) };
|
||||||
}
|
}
|
||||||
|
|
||||||
if opt.edit_config() {
|
if opt.edit_config() {
|
||||||
@@ -187,17 +187,7 @@ fn run() -> Result<()> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Self-Update step, this will execute only if:
|
step::Step::SelfUpdate.run(&mut runner, &ctx)?;
|
||||||
// 1. the `self-update` feature is enabled
|
|
||||||
// 2. it is not disabled from configuration (env var/CLI opt/file)
|
|
||||||
#[cfg(feature = "self-update")]
|
|
||||||
{
|
|
||||||
let should_self_update = env::var("TOPGRADE_NO_SELF_UPGRADE").is_err() && !config.no_self_update();
|
|
||||||
|
|
||||||
if should_self_update {
|
|
||||||
runner.execute(step::Step::SelfUpdate, "Self Update", || self_update::self_update(&ctx))?;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(windows)]
|
#[cfg(windows)]
|
||||||
let _self_rename = if config.self_rename() {
|
let _self_rename = if config.self_rename() {
|
||||||
@@ -206,20 +196,32 @@ fn run() -> Result<()> {
|
|||||||
None
|
None
|
||||||
};
|
};
|
||||||
|
|
||||||
if let Some(commands) = config.pre_commands() {
|
|
||||||
for (name, command) in commands {
|
|
||||||
generic::run_custom_command(name, command, &ctx)?;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if config.pre_sudo() {
|
if config.pre_sudo() {
|
||||||
if let Some(sudo) = ctx.sudo() {
|
if let Some(sudo) = ctx.sudo() {
|
||||||
sudo.elevate(&ctx)?;
|
sudo.elevate(&ctx)?;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if let Some(commands) = config.pre_commands() {
|
||||||
|
for (name, command) in commands {
|
||||||
|
generic::run_custom_command(name, command, &ctx)?;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
for step in step::default_steps() {
|
for step in step::default_steps() {
|
||||||
step.run(&mut runner, &ctx)?
|
match step.run(&mut runner, &ctx) {
|
||||||
|
Ok(()) => (),
|
||||||
|
Err(error)
|
||||||
|
if error
|
||||||
|
.downcast_ref::<io::Error>()
|
||||||
|
.is_some_and(|e| e.kind() == io::ErrorKind::Interrupted) =>
|
||||||
|
{
|
||||||
|
println!();
|
||||||
|
debug!("Interrupted (possibly with 'q' during retry prompt). Printing summary.");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
Err(error) => return Err(error),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut failed = false;
|
let mut failed = false;
|
||||||
@@ -320,11 +322,7 @@ fn run() -> Result<()> {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
if failed {
|
if failed { Err(StepFailed.into()) } else { Ok(()) }
|
||||||
Err(StepFailed.into())
|
|
||||||
} else {
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
|
|||||||
@@ -1,14 +1,15 @@
|
|||||||
use color_eyre::eyre::Result;
|
use color_eyre::eyre::{Result, WrapErr};
|
||||||
use rust_i18n::t;
|
use rust_i18n::t;
|
||||||
use std::borrow::Cow;
|
use std::borrow::Cow;
|
||||||
use std::fmt::Debug;
|
use std::fmt::Debug;
|
||||||
|
use std::io;
|
||||||
use tracing::debug;
|
use tracing::debug;
|
||||||
|
|
||||||
use crate::ctrlc;
|
use crate::ctrlc;
|
||||||
use crate::error::{DryRun, MissingSudo, SkipStep};
|
use crate::error::{DryRun, MissingSudo, SkipStep};
|
||||||
use crate::execution_context::ExecutionContext;
|
use crate::execution_context::ExecutionContext;
|
||||||
use crate::step::Step;
|
use crate::step::Step;
|
||||||
use crate::terminal::{print_error, print_warning, should_retry};
|
use crate::terminal::{ShouldRetry, print_error, print_warning, should_retry};
|
||||||
|
|
||||||
pub enum StepResult {
|
pub enum StepResult {
|
||||||
Success,
|
Success,
|
||||||
@@ -98,12 +99,13 @@ impl<'a> Runner<'a> {
|
|||||||
let should_ask = interrupted || !(self.ctx.config().no_retry() || ignore_failure);
|
let should_ask = interrupted || !(self.ctx.config().no_retry() || ignore_failure);
|
||||||
let should_retry = if should_ask {
|
let should_retry = if should_ask {
|
||||||
print_error(&key, format!("{e:?}"));
|
print_error(&key, format!("{e:?}"));
|
||||||
should_retry(interrupted, key.as_ref())?
|
should_retry(key.as_ref())?
|
||||||
} else {
|
} else {
|
||||||
false
|
ShouldRetry::No
|
||||||
};
|
};
|
||||||
|
|
||||||
if !should_retry {
|
match should_retry {
|
||||||
|
ShouldRetry::No | ShouldRetry::Quit => {
|
||||||
self.push_result(
|
self.push_result(
|
||||||
key,
|
key,
|
||||||
if ignore_failure {
|
if ignore_failure {
|
||||||
@@ -112,8 +114,14 @@ impl<'a> Runner<'a> {
|
|||||||
StepResult::Failure
|
StepResult::Failure
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
if let ShouldRetry::Quit = should_retry {
|
||||||
|
return Err(io::Error::from(io::ErrorKind::Interrupted))
|
||||||
|
.context("Quit from user input");
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
ShouldRetry::Yes => (),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,14 +1,14 @@
|
|||||||
use std::env;
|
use std::env;
|
||||||
#[cfg(unix)]
|
#[cfg(unix)]
|
||||||
use std::os::unix::process::CommandExt as _;
|
use std::os::unix::process::CommandExt as _;
|
||||||
|
use std::process::Command;
|
||||||
#[cfg(windows)]
|
#[cfg(windows)]
|
||||||
use std::process::exit;
|
use std::process::exit;
|
||||||
use std::process::Command;
|
|
||||||
|
|
||||||
use crate::step::Step;
|
use crate::step::Step;
|
||||||
|
use color_eyre::eyre::Result;
|
||||||
#[cfg(unix)]
|
#[cfg(unix)]
|
||||||
use color_eyre::eyre::bail;
|
use color_eyre::eyre::bail;
|
||||||
use color_eyre::eyre::Result;
|
|
||||||
use rust_i18n::t;
|
use rust_i18n::t;
|
||||||
use self_update_crate::backends::github::Update;
|
use self_update_crate::backends::github::Update;
|
||||||
use self_update_crate::update::UpdateStatus;
|
use self_update_crate::update::UpdateStatus;
|
||||||
|
|||||||
@@ -225,7 +225,7 @@ impl Step {
|
|||||||
Bin => runner.execute(*self, "bin", || generic::bin_update(ctx))?,
|
Bin => runner.execute(*self, "bin", || generic::bin_update(ctx))?,
|
||||||
Bob => runner.execute(*self, "Bob", || generic::run_bob(ctx))?,
|
Bob => runner.execute(*self, "Bob", || generic::run_bob(ctx))?,
|
||||||
BrewCask => {
|
BrewCask => {
|
||||||
#[cfg(target_os = "macos")]
|
#[cfg(any(target_os = "linux", target_os = "macos"))]
|
||||||
runner.execute(*self, "Brew Cask", || unix::run_brew_cask(ctx, unix::BrewVariant::Path))?;
|
runner.execute(*self, "Brew Cask", || unix::run_brew_cask(ctx, unix::BrewVariant::Path))?;
|
||||||
#[cfg(target_os = "macos")]
|
#[cfg(target_os = "macos")]
|
||||||
runner.execute(*self, "Brew Cask (Intel)", || {
|
runner.execute(*self, "Brew Cask (Intel)", || {
|
||||||
@@ -544,6 +544,9 @@ impl Step {
|
|||||||
runner.execute(*self, "SDKMAN!", || unix::run_sdkman(ctx))?
|
runner.execute(*self, "SDKMAN!", || unix::run_sdkman(ctx))?
|
||||||
}
|
}
|
||||||
SelfUpdate => {
|
SelfUpdate => {
|
||||||
|
// Self-Update step, this will execute only if:
|
||||||
|
// 1. the `self-update` feature is enabled
|
||||||
|
// 2. it is not disabled from configuration (env var/CLI opt/file)
|
||||||
#[cfg(feature = "self-update")]
|
#[cfg(feature = "self-update")]
|
||||||
{
|
{
|
||||||
if std::env::var("TOPGRADE_NO_SELF_UPGRADE").is_err() && !ctx.config().no_self_update() {
|
if std::env::var("TOPGRADE_NO_SELF_UPGRADE").is_err() && !ctx.config().no_self_update() {
|
||||||
@@ -747,6 +750,7 @@ pub(crate) fn default_steps() -> Vec<Step> {
|
|||||||
Restarts,
|
Restarts,
|
||||||
Flatpak,
|
Flatpak,
|
||||||
BrewFormula,
|
BrewFormula,
|
||||||
|
BrewCask,
|
||||||
Lure,
|
Lure,
|
||||||
Waydroid,
|
Waydroid,
|
||||||
AutoCpufreq,
|
AutoCpufreq,
|
||||||
|
|||||||
@@ -6,12 +6,12 @@ use std::process::Command;
|
|||||||
|
|
||||||
use color_eyre::eyre::Context;
|
use color_eyre::eyre::Context;
|
||||||
use color_eyre::eyre::Result;
|
use color_eyre::eyre::Result;
|
||||||
use color_eyre::eyre::{eyre, OptionExt};
|
use color_eyre::eyre::{OptionExt, eyre};
|
||||||
use tracing::{debug, error, warn};
|
use tracing::{debug, error, warn};
|
||||||
use wildmatch::WildMatch;
|
use wildmatch::WildMatch;
|
||||||
|
|
||||||
use crate::command::CommandExt;
|
use crate::command::CommandExt;
|
||||||
use crate::error::{self, SkipStep, TopgradeError};
|
use crate::error::{SkipStep, TopgradeError};
|
||||||
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 rust_i18n::t;
|
use rust_i18n::t;
|
||||||
@@ -185,7 +185,6 @@ pub fn run_containers(ctx: &ExecutionContext) -> Result<()> {
|
|||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut success = true;
|
|
||||||
let containers =
|
let containers =
|
||||||
list_containers(&crt, ctx.config().containers_ignored_tags()).context("Failed to list Docker containers")?;
|
list_containers(&crt, ctx.config().containers_ignored_tags()).context("Failed to list Docker containers")?;
|
||||||
debug!("Containers to inspect: {:?}", containers);
|
debug!("Containers to inspect: {:?}", containers);
|
||||||
@@ -220,22 +219,21 @@ pub fn run_containers(ctx: &ExecutionContext) -> Result<()> {
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
success = false;
|
return Err(e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if ctx.config().cleanup() {
|
if ctx.config().containers_system_prune() {
|
||||||
|
// Run system prune to clean up unused containers, networks, and build cache
|
||||||
|
ctx.execute(&crt)
|
||||||
|
.args(["system", "prune", "--force"])
|
||||||
|
.status_checked()?
|
||||||
|
// Only run `image prune` if we don't run `system prune`
|
||||||
|
} else if ctx.config().cleanup() {
|
||||||
// Remove dangling images
|
// Remove dangling images
|
||||||
debug!("Removing dangling images");
|
debug!("Removing dangling images");
|
||||||
if let Err(e) = ctx.execute(&crt).args(["image", "prune", "-f"]).status_checked() {
|
ctx.execute(&crt).args(["image", "prune", "-f"]).status_checked()?
|
||||||
error!("Removing dangling images failed: {}", e);
|
|
||||||
success = false;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if success {
|
|
||||||
Ok(())
|
Ok(())
|
||||||
} else {
|
|
||||||
Err(eyre!(error::StepFailed))
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ use crate::command::CommandExt;
|
|||||||
use crate::execution_context::ExecutionContext;
|
use crate::execution_context::ExecutionContext;
|
||||||
use crate::step::Step;
|
use crate::step::Step;
|
||||||
use crate::terminal::print_separator;
|
use crate::terminal::print_separator;
|
||||||
use crate::utils::{require, require_option, PathExt};
|
use crate::utils::{PathExt, require, require_option};
|
||||||
|
|
||||||
const EMACS_UPGRADE: &str = include_str!("emacs.el");
|
const EMACS_UPGRADE: &str = include_str!("emacs.el");
|
||||||
#[cfg(windows)]
|
#[cfg(windows)]
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
use color_eyre::eyre::Context;
|
use color_eyre::eyre::Context;
|
||||||
use color_eyre::eyre::Result;
|
use color_eyre::eyre::Result;
|
||||||
use color_eyre::eyre::{eyre, OptionExt};
|
use color_eyre::eyre::{OptionExt, eyre};
|
||||||
use jetbrains_toolbox_updater::{find_jetbrains_toolbox, update_jetbrains_toolbox, FindError};
|
use jetbrains_toolbox_updater::{FindError, find_jetbrains_toolbox, update_jetbrains_toolbox};
|
||||||
use regex::bytes::Regex;
|
use regex::bytes::Regex;
|
||||||
use rust_i18n::t;
|
use rust_i18n::t;
|
||||||
use semver::Version;
|
use semver::Version;
|
||||||
@@ -16,6 +16,7 @@ use std::{fs, io::Write};
|
|||||||
use tempfile::tempfile_in;
|
use tempfile::tempfile_in;
|
||||||
use tracing::{debug, error, warn};
|
use tracing::{debug, error, warn};
|
||||||
|
|
||||||
|
use crate::HOME_DIR;
|
||||||
use crate::command::{CommandExt, Utf8Output};
|
use crate::command::{CommandExt, Utf8Output};
|
||||||
use crate::execution_context::ExecutionContext;
|
use crate::execution_context::ExecutionContext;
|
||||||
use crate::executor::ExecutorOutput;
|
use crate::executor::ExecutorOutput;
|
||||||
@@ -23,8 +24,7 @@ use crate::output_changed_message;
|
|||||||
use crate::step::Step;
|
use crate::step::Step;
|
||||||
use crate::sudo::SudoExecuteOpts;
|
use crate::sudo::SudoExecuteOpts;
|
||||||
use crate::terminal::{print_separator, shell};
|
use crate::terminal::{print_separator, shell};
|
||||||
use crate::utils::{check_is_python_2_or_shim, require, require_one, require_option, which, PathExt};
|
use crate::utils::{PathExt, check_is_python_2_or_shim, require, require_one, require_option, which};
|
||||||
use crate::HOME_DIR;
|
|
||||||
use crate::{
|
use crate::{
|
||||||
error::{SkipStep, StepFailed, TopgradeError},
|
error::{SkipStep, StepFailed, TopgradeError},
|
||||||
terminal::print_warning,
|
terminal::print_warning,
|
||||||
@@ -65,7 +65,9 @@ pub fn run_cargo_update(ctx: &ExecutionContext) -> Result<()> {
|
|||||||
.or_else(|| cargo_dir.join("bin/cargo-install-update").if_exists());
|
.or_else(|| cargo_dir.join("bin/cargo-install-update").if_exists());
|
||||||
|
|
||||||
let Some(cargo_update) = cargo_update else {
|
let Some(cargo_update) = cargo_update else {
|
||||||
let message = String::from("cargo-update isn't installed so Topgrade can't upgrade cargo packages.\nInstall cargo-update by running `cargo install cargo-update`");
|
let message = String::from(
|
||||||
|
"cargo-update isn't installed so Topgrade can't upgrade cargo packages.\nInstall cargo-update by running `cargo install cargo-update`",
|
||||||
|
);
|
||||||
print_warning(&message);
|
print_warning(&message);
|
||||||
return Err(SkipStep(message).into());
|
return Err(SkipStep(message).into());
|
||||||
};
|
};
|
||||||
@@ -81,7 +83,9 @@ pub fn run_cargo_update(ctx: &ExecutionContext) -> Result<()> {
|
|||||||
if let Some(e) = cargo_cache {
|
if let Some(e) = cargo_cache {
|
||||||
ctx.execute(e).args(["-a"]).status_checked()?;
|
ctx.execute(e).args(["-a"]).status_checked()?;
|
||||||
} else {
|
} else {
|
||||||
let message = String::from("cargo-cache isn't installed so Topgrade can't cleanup cargo packages.\nInstall cargo-cache by running `cargo install cargo-cache`");
|
let message = String::from(
|
||||||
|
"cargo-cache isn't installed so Topgrade can't cleanup cargo packages.\nInstall cargo-cache by running `cargo install cargo-cache`",
|
||||||
|
);
|
||||||
print_warning(message);
|
print_warning(message);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -282,6 +286,17 @@ pub fn run_elan(ctx: &ExecutionContext) -> Result<()> {
|
|||||||
|
|
||||||
print_separator("elan");
|
print_separator("elan");
|
||||||
|
|
||||||
|
let version_output = ctx.execute(&elan).arg("--version").output_checked_utf8()?;
|
||||||
|
let version_string = version_output.stdout.split_whitespace().nth(1).ok_or_else(|| {
|
||||||
|
eyre!(output_changed_message!(
|
||||||
|
"elan --version",
|
||||||
|
"Expected version after 'elan '"
|
||||||
|
))
|
||||||
|
})?;
|
||||||
|
let version = Version::parse(version_string)
|
||||||
|
.wrap_err_with(|| output_changed_message!("elan --version", "Invalid version"))?;
|
||||||
|
debug!("Detected elan version as: {}", version);
|
||||||
|
|
||||||
let disabled_error_msg = "self-update is disabled";
|
let disabled_error_msg = "self-update is disabled";
|
||||||
let executor_output = ctx.execute(&elan).args(["self", "update"]).output()?;
|
let executor_output = ctx.execute(&elan).args(["self", "update"]).output()?;
|
||||||
match executor_output {
|
match executor_output {
|
||||||
@@ -310,7 +325,12 @@ pub fn run_elan(ctx: &ExecutionContext) -> Result<()> {
|
|||||||
ExecutorOutput::Dry => { /* nothing needed because in a dry run */ }
|
ExecutorOutput::Dry => { /* nothing needed because in a dry run */ }
|
||||||
}
|
}
|
||||||
|
|
||||||
ctx.execute(&elan).arg("update").status_checked()
|
// In elan 4.0.0, `elan update` was removed, as toolchains are now updated automatically
|
||||||
|
if version < Version::new(4, 0, 0) {
|
||||||
|
ctx.execute(&elan).arg("update").status_checked()?;
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn run_juliaup(ctx: &ExecutionContext) -> Result<()> {
|
pub fn run_juliaup(ctx: &ExecutionContext) -> Result<()> {
|
||||||
@@ -526,7 +546,7 @@ fn run_vscode_compatible(variant: VSCodeVariant, ctx: &ExecutionContext) -> Resu
|
|||||||
return Err(eyre!(output_changed_message!(
|
return Err(eyre!(output_changed_message!(
|
||||||
&format!("{bin_name} --version"),
|
&format!("{bin_name} --version"),
|
||||||
"No first line"
|
"No first line"
|
||||||
)))
|
)));
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -873,12 +893,11 @@ pub fn run_tldr(ctx: &ExecutionContext) -> Result<()> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn run_tlmgr_update(ctx: &ExecutionContext) -> Result<()> {
|
pub fn run_tlmgr_update(ctx: &ExecutionContext) -> Result<()> {
|
||||||
cfg_if::cfg_if! {
|
if cfg!(any(target_os = "linux", target_os = "android")) && !ctx.config().enable_tlmgr_linux() {
|
||||||
if #[cfg(any(target_os = "linux", target_os = "android"))] {
|
return Err(SkipStep(String::from(
|
||||||
if !ctx.config().enable_tlmgr_linux() {
|
"tlmgr must be explicitly enabled in the configuration to run in Android/Linux",
|
||||||
return Err(SkipStep(String::from("tlmgr must be explicitly enabled in the configuration to run in Android/Linux")).into());
|
))
|
||||||
}
|
.into());
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
let tlmgr = require("tlmgr")?;
|
let tlmgr = require("tlmgr")?;
|
||||||
@@ -916,9 +935,17 @@ pub fn run_chezmoi_update(ctx: &ExecutionContext) -> Result<()> {
|
|||||||
let chezmoi = require("chezmoi")?;
|
let chezmoi = require("chezmoi")?;
|
||||||
HOME_DIR.join(".local/share/chezmoi").require()?;
|
HOME_DIR.join(".local/share/chezmoi").require()?;
|
||||||
|
|
||||||
|
let mut cmd = ctx.execute(chezmoi);
|
||||||
|
|
||||||
print_separator("chezmoi");
|
print_separator("chezmoi");
|
||||||
|
|
||||||
ctx.execute(chezmoi).arg("update").status_checked()
|
cmd.arg("update");
|
||||||
|
|
||||||
|
if ctx.config().chezmoi_exclude_encrypted() {
|
||||||
|
cmd.arg("--exclude=encrypted");
|
||||||
|
}
|
||||||
|
|
||||||
|
cmd.status_checked()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn run_myrepos_update(ctx: &ExecutionContext) -> Result<()> {
|
pub fn run_myrepos_update(ctx: &ExecutionContext) -> Result<()> {
|
||||||
@@ -975,25 +1002,21 @@ pub fn run_composer_update(ctx: &ExecutionContext) -> Result<()> {
|
|||||||
print_separator(t!("Composer"));
|
print_separator(t!("Composer"));
|
||||||
|
|
||||||
if ctx.config().composer_self_update() {
|
if ctx.config().composer_self_update() {
|
||||||
cfg_if::cfg_if! {
|
if cfg!(unix) {
|
||||||
if #[cfg(unix)] {
|
|
||||||
// If self-update fails without sudo then there's probably an update
|
// If self-update fails without sudo then there's probably an update
|
||||||
let has_update = match ctx.execute(&composer).arg("self-update").output()? {
|
let has_update = match ctx.execute(&composer).arg("self-update").output()? {
|
||||||
ExecutorOutput::Wet(output) => !output.status.success(),
|
ExecutorOutput::Wet(output) => !output.status.success(),
|
||||||
_ => false
|
_ => false,
|
||||||
};
|
};
|
||||||
|
|
||||||
if has_update {
|
if has_update {
|
||||||
let sudo = ctx.require_sudo()?;
|
let sudo = ctx.require_sudo()?;
|
||||||
sudo.execute(ctx, &composer)?
|
sudo.execute(ctx, &composer)?.arg("self-update").status_checked()?;
|
||||||
.arg("self-update")
|
|
||||||
.status_checked()?;
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
ctx.execute(&composer).arg("self-update").status_checked()?;
|
ctx.execute(&composer).arg("self-update").status_checked()?;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
let output = ctx.execute(&composer).args(["global", "update"]).output()?;
|
let output = ctx.execute(&composer).args(["global", "update"]).output()?;
|
||||||
if let ExecutorOutput::Wet(output) = output {
|
if let ExecutorOutput::Wet(output) = output {
|
||||||
@@ -1220,11 +1243,7 @@ pub fn run_helm_repo_update(ctx: &ExecutionContext) -> Result<()> {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
if success {
|
if success { Ok(()) } else { Err(eyre!(StepFailed)) }
|
||||||
Ok(())
|
|
||||||
} else {
|
|
||||||
Err(eyre!(StepFailed))
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn run_stew(ctx: &ExecutionContext) -> Result<()> {
|
pub fn run_stew(ctx: &ExecutionContext) -> Result<()> {
|
||||||
@@ -1409,8 +1428,7 @@ pub fn run_poetry(ctx: &ExecutionContext) -> Result<()> {
|
|||||||
.map_err(|e| SkipStep(format!("Could not find interpreter for {}: {}", poetry.display(), e)))?;
|
.map_err(|e| SkipStep(format!("Could not find interpreter for {}: {}", poetry.display(), e)))?;
|
||||||
debug!("poetry interpreter: {:?}, args: {:?}", interp, interp_args);
|
debug!("poetry interpreter: {:?}, args: {:?}", interp, interp_args);
|
||||||
|
|
||||||
let check_official_install_script =
|
let check_official_install_script = "import sys; from os import path; print('Y') if path.isfile(path.join(sys.prefix, 'poetry_env')) else print('N')";
|
||||||
"import sys; from os import path; print('Y') if path.isfile(path.join(sys.prefix, 'poetry_env')) else print('N')";
|
|
||||||
let mut command = Command::new(&interp);
|
let mut command = Command::new(&interp);
|
||||||
if let Some(args) = interp_args {
|
if let Some(args) = interp_args {
|
||||||
command.arg(args);
|
command.arg(args);
|
||||||
@@ -1561,9 +1579,25 @@ pub fn run_zvm(ctx: &ExecutionContext) -> Result<()> {
|
|||||||
pub fn run_bun(ctx: &ExecutionContext) -> Result<()> {
|
pub fn run_bun(ctx: &ExecutionContext) -> Result<()> {
|
||||||
let bun = require("bun")?;
|
let bun = require("bun")?;
|
||||||
|
|
||||||
|
// From the official install script (both install.sh and install.ps1), Bun uses
|
||||||
|
// the path set in this variable as the install root, and its defaults to
|
||||||
|
// `$HOME/.bun`
|
||||||
|
//
|
||||||
|
// UNIX: https://bun.sh/install.sh
|
||||||
|
// Windows: https://bun.sh/install.ps1
|
||||||
|
let bun_install_env = env::var("BUN_INSTALL")
|
||||||
|
.map(PathBuf::from)
|
||||||
|
.unwrap_or(HOME_DIR.join(".bun"));
|
||||||
|
|
||||||
|
// If `bun` is a descendant of `bun_install_env`, then Bun is installed
|
||||||
|
// through the official script
|
||||||
|
if bun.is_descendant_of(&bun_install_env) {
|
||||||
print_separator("Bun");
|
print_separator("Bun");
|
||||||
|
|
||||||
ctx.execute(bun).arg("upgrade").status_checked()
|
ctx.execute(bun).arg("upgrade").status_checked()
|
||||||
|
} else {
|
||||||
|
Err(SkipStep("Not installed through the official script".to_string()).into())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn run_zigup(ctx: &ExecutionContext) -> Result<()> {
|
pub fn run_zigup(ctx: &ExecutionContext) -> Result<()> {
|
||||||
@@ -1673,7 +1707,10 @@ fn run_jetbrains_ide_generic<const IS_JETBRAINS: bool>(ctx: &ExecutionContext, b
|
|||||||
.code()
|
.code()
|
||||||
.ok_or_eyre("Failed to get status code; was killed with signal")?;
|
.ok_or_eyre("Failed to get status code; was killed with signal")?;
|
||||||
if status_code != 1 {
|
if status_code != 1 {
|
||||||
return Err(eyre!("Expected status code 1 ('Only one instance of <IDE> can be run at a time.'), but found status code {}. Output: {output:?}", status_code));
|
return Err(eyre!(
|
||||||
|
"Expected status code 1 ('Only one instance of <IDE> can be run at a time.'), but found status code {}. Output: {output:?}",
|
||||||
|
status_code
|
||||||
|
));
|
||||||
}
|
}
|
||||||
// Don't crash, but don't be silent either
|
// Don't crash, but don't be silent either
|
||||||
warn!("{name} is already running, can't update it now.");
|
warn!("{name} is already running, can't update it now.");
|
||||||
|
|||||||
@@ -4,10 +4,10 @@ use std::path::{Path, PathBuf};
|
|||||||
use std::process::{Command, Output, Stdio};
|
use std::process::{Command, Output, Stdio};
|
||||||
|
|
||||||
use color_eyre::eyre::Context;
|
use color_eyre::eyre::Context;
|
||||||
use color_eyre::eyre::{eyre, Result};
|
use color_eyre::eyre::{Result, eyre};
|
||||||
use console::style;
|
use console::style;
|
||||||
use futures::stream::{iter, FuturesUnordered, StreamExt};
|
use futures::stream::{FuturesUnordered, StreamExt, iter};
|
||||||
use glob::{glob_with, MatchOptions};
|
use glob::{MatchOptions, glob_with};
|
||||||
use tokio::process::Command as AsyncCommand;
|
use tokio::process::Command as AsyncCommand;
|
||||||
use tokio::runtime;
|
use tokio::runtime;
|
||||||
use tracing::{debug, error};
|
use tracing::{debug, error};
|
||||||
@@ -17,8 +17,8 @@ use crate::execution_context::ExecutionContext;
|
|||||||
use crate::step::Step;
|
use crate::step::Step;
|
||||||
use crate::steps::emacs::Emacs;
|
use crate::steps::emacs::Emacs;
|
||||||
use crate::terminal::print_separator;
|
use crate::terminal::print_separator;
|
||||||
use crate::utils::{require, PathExt};
|
use crate::utils::{PathExt, require};
|
||||||
use crate::{error::SkipStep, terminal::print_warning, HOME_DIR};
|
use crate::{HOME_DIR, error::SkipStep, terminal::print_warning};
|
||||||
use etcetera::base_strategy::BaseStrategy;
|
use etcetera::base_strategy::BaseStrategy;
|
||||||
use rust_i18n::t;
|
use rust_i18n::t;
|
||||||
|
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ use tracing::debug;
|
|||||||
|
|
||||||
use crate::command::CommandExt;
|
use crate::command::CommandExt;
|
||||||
use crate::terminal::{print_info, print_separator};
|
use crate::terminal::{print_info, print_separator};
|
||||||
use crate::utils::{require, PathExt};
|
use crate::utils::{PathExt, require};
|
||||||
use crate::{error::SkipStep, execution_context::ExecutionContext};
|
use crate::{error::SkipStep, execution_context::ExecutionContext};
|
||||||
|
|
||||||
enum NPMVariant {
|
enum NPMVariant {
|
||||||
@@ -65,11 +65,7 @@ impl NPM {
|
|||||||
/// If the “NPM” version is larger than 8.11.0, we use
|
/// If the “NPM” version is larger than 8.11.0, we use
|
||||||
/// `--location=global`; otherwise, use `-g`.
|
/// `--location=global`; otherwise, use `-g`.
|
||||||
fn global_location_arg(&self) -> &str {
|
fn global_location_arg(&self) -> &str {
|
||||||
if self.is_npm_8() {
|
if self.is_npm_8() { "--location=global" } else { "-g" }
|
||||||
"--location=global"
|
|
||||||
} else {
|
|
||||||
"-g"
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(target_os = "linux")]
|
#[cfg(target_os = "linux")]
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ use ini::Ini;
|
|||||||
use rust_i18n::t;
|
use rust_i18n::t;
|
||||||
use tracing::{debug, warn};
|
use tracing::{debug, warn};
|
||||||
|
|
||||||
|
use crate::HOME_DIR;
|
||||||
use crate::command::CommandExt;
|
use crate::command::CommandExt;
|
||||||
use crate::error::{SkipStep, TopgradeError};
|
use crate::error::{SkipStep, TopgradeError};
|
||||||
use crate::execution_context::ExecutionContext;
|
use crate::execution_context::ExecutionContext;
|
||||||
@@ -14,8 +15,7 @@ use crate::steps::generic::is_wsl;
|
|||||||
use crate::steps::os::archlinux;
|
use crate::steps::os::archlinux;
|
||||||
use crate::sudo::SudoExecuteOpts;
|
use crate::sudo::SudoExecuteOpts;
|
||||||
use crate::terminal::{print_separator, prompt_yesno};
|
use crate::terminal::{print_separator, prompt_yesno};
|
||||||
use crate::utils::{require, require_one, which, PathExt};
|
use crate::utils::{PathExt, require, require_one, which};
|
||||||
use crate::HOME_DIR;
|
|
||||||
|
|
||||||
static OS_RELEASE_PATH: &str = "/etc/os-release";
|
static OS_RELEASE_PATH: &str = "/etc/os-release";
|
||||||
|
|
||||||
@@ -78,6 +78,8 @@ impl Distribution {
|
|||||||
Some("neon") => Distribution::KDENeon,
|
Some("neon") => Distribution::KDENeon,
|
||||||
Some("openmandriva") => Distribution::OpenMandriva,
|
Some("openmandriva") => Distribution::OpenMandriva,
|
||||||
Some("pclinuxos") => Distribution::PCLinuxOS,
|
Some("pclinuxos") => Distribution::PCLinuxOS,
|
||||||
|
Some(id) if id.starts_with("origami") => Distribution::FedoraImmutable,
|
||||||
|
|
||||||
_ => {
|
_ => {
|
||||||
if let Some(name) = name {
|
if let Some(name) = name {
|
||||||
if name.contains("Vanilla") {
|
if name.contains("Vanilla") {
|
||||||
@@ -1341,4 +1343,11 @@ mod tests {
|
|||||||
fn test_cachyos() {
|
fn test_cachyos() {
|
||||||
test_template(include_str!("os_release/cachyos"), Distribution::Arch);
|
test_template(include_str!("os_release/cachyos"), Distribution::Arch);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_origami() {
|
||||||
|
test_template(include_str!("os_release/origami"), Distribution::FedoraImmutable);
|
||||||
|
test_template(include_str!("os_release/origami-nvidia"), Distribution::FedoraImmutable);
|
||||||
|
test_template(include_str!("os_release/origami-test"), Distribution::FedoraImmutable);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -200,7 +200,7 @@ pub fn update_xcodes(ctx: &ExecutionContext) -> Result<()> {
|
|||||||
pub fn process_xcodes_releases(releases_filtered: Vec<String>, should_ask: bool, ctx: &ExecutionContext) -> Result<()> {
|
pub fn process_xcodes_releases(releases_filtered: Vec<String>, should_ask: bool, ctx: &ExecutionContext) -> Result<()> {
|
||||||
let xcodes = require("xcodes")?;
|
let xcodes = require("xcodes")?;
|
||||||
|
|
||||||
if releases_filtered.last().map_or(true, |s| !s.contains("(Installed)")) && !releases_filtered.is_empty() {
|
if releases_filtered.last().is_none_or(|s| !s.contains("(Installed)")) && !releases_filtered.is_empty() {
|
||||||
println!(
|
println!(
|
||||||
"{} {}",
|
"{} {}",
|
||||||
t!("New Xcode release detected:"),
|
t!("New Xcode release detected:"),
|
||||||
|
|||||||
@@ -1,20 +1,17 @@
|
|||||||
use crate::command::CommandExt;
|
use crate::command::CommandExt;
|
||||||
use crate::execution_context::ExecutionContext;
|
use crate::execution_context::ExecutionContext;
|
||||||
use crate::executor::RunType;
|
|
||||||
use crate::terminal::print_separator;
|
use crate::terminal::print_separator;
|
||||||
use color_eyre::eyre::Result;
|
use color_eyre::eyre::Result;
|
||||||
use rust_i18n::t;
|
use rust_i18n::t;
|
||||||
use std::fs;
|
use std::fs;
|
||||||
|
use tracing::debug;
|
||||||
|
|
||||||
fn is_openbsd_current(ctx: &ExecutionContext) -> Result<bool> {
|
fn is_openbsd_current() -> Result<bool> {
|
||||||
let motd_content = fs::read_to_string("/etc/motd")?;
|
let motd_content = fs::read_to_string("/etc/motd")?;
|
||||||
let is_current = ["-current", "-beta"].iter().any(|&s| motd_content.contains(s));
|
let is_current = ["-current", "-beta"].iter().any(|&s| motd_content.contains(s));
|
||||||
match ctx.config.run_type() {
|
|
||||||
RunType::Dry | RunType::Damp => {
|
debug!("OpenBSD is -current/-beta: {is_current}");
|
||||||
println!("{}", t!("Checking if /etc/motd contains -current or -beta"));
|
|
||||||
}
|
|
||||||
RunType::Wet => {}
|
|
||||||
}
|
|
||||||
Ok(is_current)
|
Ok(is_current)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -23,12 +20,7 @@ pub fn upgrade_openbsd(ctx: &ExecutionContext) -> Result<()> {
|
|||||||
|
|
||||||
let sudo = ctx.require_sudo()?;
|
let sudo = ctx.require_sudo()?;
|
||||||
|
|
||||||
let is_current = is_openbsd_current(ctx)?;
|
let is_current = is_openbsd_current()?;
|
||||||
|
|
||||||
if ctx.config().dry_run() {
|
|
||||||
println!("{}", t!("Would upgrade the OpenBSD system"));
|
|
||||||
return Ok(());
|
|
||||||
}
|
|
||||||
|
|
||||||
if is_current {
|
if is_current {
|
||||||
sudo.execute(ctx, "/usr/sbin/sysupgrade")?.arg("-sn").status_checked()
|
sudo.execute(ctx, "/usr/sbin/sysupgrade")?.arg("-sn").status_checked()
|
||||||
@@ -42,7 +34,7 @@ pub fn upgrade_packages(ctx: &ExecutionContext) -> Result<()> {
|
|||||||
|
|
||||||
let sudo = ctx.require_sudo()?;
|
let sudo = ctx.require_sudo()?;
|
||||||
|
|
||||||
let is_current = is_openbsd_current(ctx)?;
|
let is_current = is_openbsd_current()?;
|
||||||
|
|
||||||
if ctx.config().cleanup() {
|
if ctx.config().cleanup() {
|
||||||
sudo.execute(ctx, "/usr/sbin/pkg_delete")?.arg("-ac").status_checked()?;
|
sudo.execute(ctx, "/usr/sbin/pkg_delete")?.arg("-ac").status_checked()?;
|
||||||
|
|||||||
23
src/steps/os/os_release/origami
Normal file
23
src/steps/os/os_release/origami
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
NAME="Origami Linux"
|
||||||
|
VERSION="43.20251117.0 (COSMIC Atomic)"
|
||||||
|
RELEASE_TYPE="stable"
|
||||||
|
ID="origami-linux"
|
||||||
|
VERSION_ID="43"
|
||||||
|
VERSION_CODENAME=""
|
||||||
|
PRETTY_NAME="Origami 折り紙"
|
||||||
|
ANSI_COLOR="0;38;2;60;110;180"
|
||||||
|
LOGO="fedora-logo-icon"
|
||||||
|
CPE_NAME="cpe:/o:fedoraproject:fedora:43"
|
||||||
|
DEFAULT_HOSTNAME="origami"
|
||||||
|
HOME_URL="https://origami.wf/"
|
||||||
|
DOCUMENTATION_URL="https://docs.fedoraproject.org/en-US/fedora/f43/"
|
||||||
|
SUPPORT_URL="https://ask.fedoraproject.org/"
|
||||||
|
BUG_REPORT_URL="https://gitlab.com/groups/origami-linux/-/issues"
|
||||||
|
REDHAT_BUGZILLA_PRODUCT="Fedora"
|
||||||
|
REDHAT_BUGZILLA_PRODUCT_VERSION="43"
|
||||||
|
REDHAT_SUPPORT_PRODUCT="Fedora"
|
||||||
|
REDHAT_SUPPORT_PRODUCT_VERSION="43"
|
||||||
|
SUPPORT_END="2026-12-02"
|
||||||
|
VARIANT="COSMIC Atomic"
|
||||||
|
VARIANT_ID="cosmic-atomic"
|
||||||
|
OSTREE_VERSION="43.20251117.0"
|
||||||
23
src/steps/os/os_release/origami-nvidia
Normal file
23
src/steps/os/os_release/origami-nvidia
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
NAME="Origami Linux Nvidia"
|
||||||
|
VERSION="43.20251117.0 (COSMIC Atomic)"
|
||||||
|
RELEASE_TYPE="stable"
|
||||||
|
ID="origami-linux-nvidia"
|
||||||
|
VERSION_ID="43"
|
||||||
|
VERSION_CODENAME=""
|
||||||
|
PRETTY_NAME="Origami 折り紙"
|
||||||
|
ANSI_COLOR="0;38;2;60;110;180"
|
||||||
|
LOGO="fedora-logo-icon"
|
||||||
|
CPE_NAME="cpe:/o:fedoraproject:fedora:43"
|
||||||
|
DEFAULT_HOSTNAME="origami"
|
||||||
|
HOME_URL="https://origami.wf/"
|
||||||
|
DOCUMENTATION_URL="https://docs.fedoraproject.org/en-US/fedora/f43/"
|
||||||
|
SUPPORT_URL="https://ask.fedoraproject.org/"
|
||||||
|
BUG_REPORT_URL="https://gitlab.com/groups/origami-linux/-/issues"
|
||||||
|
REDHAT_BUGZILLA_PRODUCT="Fedora"
|
||||||
|
REDHAT_BUGZILLA_PRODUCT_VERSION="43"
|
||||||
|
REDHAT_SUPPORT_PRODUCT="Fedora"
|
||||||
|
REDHAT_SUPPORT_PRODUCT_VERSION="43"
|
||||||
|
SUPPORT_END="2026-12-02"
|
||||||
|
VARIANT="COSMIC Atomic"
|
||||||
|
VARIANT_ID="cosmic-atomic"
|
||||||
|
OSTREE_VERSION="43.20251117.0"
|
||||||
23
src/steps/os/os_release/origami-test
Normal file
23
src/steps/os/os_release/origami-test
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
NAME="Origami Linux Test"
|
||||||
|
VERSION="43.20251117.0 (COSMIC Atomic)"
|
||||||
|
RELEASE_TYPE="stable"
|
||||||
|
ID="origami-linux-test"
|
||||||
|
VERSION_ID="43"
|
||||||
|
VERSION_CODENAME=""
|
||||||
|
PRETTY_NAME="Origami 折り紙"
|
||||||
|
ANSI_COLOR="0;38;2;60;110;180"
|
||||||
|
LOGO="fedora-logo-icon"
|
||||||
|
CPE_NAME="cpe:/o:fedoraproject:fedora:43"
|
||||||
|
DEFAULT_HOSTNAME="origami"
|
||||||
|
HOME_URL="https://origami.wf/"
|
||||||
|
DOCUMENTATION_URL="https://docs.fedoraproject.org/en-US/fedora/f43/"
|
||||||
|
SUPPORT_URL="https://ask.fedoraproject.org/"
|
||||||
|
BUG_REPORT_URL="https://gitlab.com/groups/origami-linux/-/issues"
|
||||||
|
REDHAT_BUGZILLA_PRODUCT="Fedora"
|
||||||
|
REDHAT_BUGZILLA_PRODUCT_VERSION="43"
|
||||||
|
REDHAT_SUPPORT_PRODUCT="Fedora"
|
||||||
|
REDHAT_SUPPORT_PRODUCT_VERSION="43"
|
||||||
|
SUPPORT_END="2026-12-02"
|
||||||
|
VARIANT="COSMIC Atomic"
|
||||||
|
VARIANT_ID="cosmic-atomic"
|
||||||
|
OSTREE_VERSION="43.20251117.0"
|
||||||
@@ -1,14 +1,14 @@
|
|||||||
use color_eyre::eyre::Context;
|
use color_eyre::eyre::Context;
|
||||||
use color_eyre::eyre::Result;
|
use color_eyre::eyre::Result;
|
||||||
use color_eyre::eyre::{eyre, OptionExt};
|
use color_eyre::eyre::{OptionExt, eyre};
|
||||||
use etcetera::BaseStrategy;
|
use etcetera::BaseStrategy;
|
||||||
use home;
|
|
||||||
use ini::Ini;
|
use ini::Ini;
|
||||||
#[cfg(target_os = "linux")]
|
#[cfg(target_os = "linux")]
|
||||||
use nix::unistd::Uid;
|
use nix::unistd::Uid;
|
||||||
use regex::Regex;
|
use regex::Regex;
|
||||||
use rust_i18n::t;
|
use rust_i18n::t;
|
||||||
use semver::Version;
|
use semver::Version;
|
||||||
|
use std::env::home_dir;
|
||||||
use std::ffi::OsStr;
|
use std::ffi::OsStr;
|
||||||
use std::io::Write;
|
use std::io::Write;
|
||||||
use std::os::unix::fs::MetadataExt;
|
use std::os::unix::fs::MetadataExt;
|
||||||
@@ -20,10 +20,10 @@ use std::{env::var, path::Path};
|
|||||||
use std::{fs, io};
|
use std::{fs, io};
|
||||||
use tracing::{debug, warn};
|
use tracing::{debug, warn};
|
||||||
|
|
||||||
|
use crate::XDG_DIRS;
|
||||||
use crate::command::CommandExt;
|
use crate::command::CommandExt;
|
||||||
use crate::sudo::SudoExecuteOpts;
|
use crate::sudo::SudoExecuteOpts;
|
||||||
use crate::XDG_DIRS;
|
use crate::{HOME_DIR, output_changed_message};
|
||||||
use crate::{output_changed_message, HOME_DIR};
|
|
||||||
|
|
||||||
#[cfg(target_os = "linux")]
|
#[cfg(target_os = "linux")]
|
||||||
use super::linux::Distribution;
|
use super::linux::Distribution;
|
||||||
@@ -33,7 +33,7 @@ use crate::execution_context::ExecutionContext;
|
|||||||
use crate::executor::Executor;
|
use crate::executor::Executor;
|
||||||
use crate::step::Step;
|
use crate::step::Step;
|
||||||
use crate::terminal::print_separator;
|
use crate::terminal::print_separator;
|
||||||
use crate::utils::{require, PathExt};
|
use crate::utils::{PathExt, require};
|
||||||
|
|
||||||
#[cfg(any(target_os = "linux", target_os = "macos"))]
|
#[cfg(any(target_os = "linux", target_os = "macos"))]
|
||||||
const INTEL_BREW: &str = "/usr/local/bin/brew";
|
const INTEL_BREW: &str = "/usr/local/bin/brew";
|
||||||
@@ -81,7 +81,6 @@ impl BrewVariant {
|
|||||||
/// Execute an "internal" brew command, i.e. one that should always be run
|
/// Execute an "internal" brew command, i.e. one that should always be run
|
||||||
/// even when dry-running. Basically just a wrapper around [`Command::new`]
|
/// even when dry-running. Basically just a wrapper around [`Command::new`]
|
||||||
/// that uses `arch` to run using the correct architecture if needed.
|
/// that uses `arch` to run using the correct architecture if needed.
|
||||||
#[cfg(target_os = "macos")]
|
|
||||||
fn execute_internal(self) -> Command {
|
fn execute_internal(self) -> Command {
|
||||||
match self {
|
match self {
|
||||||
BrewVariant::MacIntel if cfg!(target_arch = "aarch64") => {
|
BrewVariant::MacIntel if cfg!(target_arch = "aarch64") => {
|
||||||
@@ -365,12 +364,48 @@ pub fn run_brew_formula(ctx: &ExecutionContext, variant: BrewVariant) -> Result<
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(target_os = "macos")]
|
#[cfg(any(target_os = "linux", target_os = "macos"))]
|
||||||
pub fn run_brew_cask(ctx: &ExecutionContext, variant: BrewVariant) -> Result<()> {
|
pub fn run_brew_cask(ctx: &ExecutionContext, variant: BrewVariant) -> Result<()> {
|
||||||
let binary_name = require(variant.binary_name())?;
|
let binary_name = require(variant.binary_name())?;
|
||||||
|
|
||||||
|
#[cfg(target_os = "macos")]
|
||||||
if variant.is_path() && !BrewVariant::is_macos_custom(binary_name) {
|
if variant.is_path() && !BrewVariant::is_macos_custom(binary_name) {
|
||||||
return Err(SkipStep(t!("Not a custom brew for macOS").to_string()).into());
|
return Err(SkipStep(t!("Not a custom brew for macOS").to_string()).into());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(target_os = "linux")]
|
||||||
|
{
|
||||||
|
// Homebrew cask support was added in version 4.5.0
|
||||||
|
let version_output = Command::new(&binary_name).arg("--version").output_checked_utf8()?;
|
||||||
|
|
||||||
|
let version_line = version_output
|
||||||
|
.stdout
|
||||||
|
.lines()
|
||||||
|
.next()
|
||||||
|
.ok_or_else(|| eyre!(output_changed_message!("brew --version", "no output lines")))?;
|
||||||
|
|
||||||
|
let version_str = version_line.split_whitespace().nth(1).ok_or_else(|| {
|
||||||
|
eyre!(output_changed_message!(
|
||||||
|
"brew --version",
|
||||||
|
"Expected version after 'Homebrew'"
|
||||||
|
))
|
||||||
|
})?;
|
||||||
|
|
||||||
|
let version = Version::parse(version_str)
|
||||||
|
.wrap_err_with(|| output_changed_message!("brew --version", "Invalid version"))?;
|
||||||
|
|
||||||
|
if version < Version::new(4, 5, 0) {
|
||||||
|
return Err(SkipStep(
|
||||||
|
t!(
|
||||||
|
"Homebrew cask support on Linux requires Homebrew 4.5.0 or later (found {version})",
|
||||||
|
version = version
|
||||||
|
)
|
||||||
|
.to_string(),
|
||||||
|
)
|
||||||
|
.into());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
print_separator(format!("{} - Cask", variant.step_title()));
|
print_separator(format!("{} - Cask", variant.step_title()));
|
||||||
|
|
||||||
let cask_upgrade_exists = variant
|
let cask_upgrade_exists = variant
|
||||||
@@ -491,8 +526,8 @@ pub fn run_nix(ctx: &ExecutionContext) -> Result<()> {
|
|||||||
let nix = require("nix")?;
|
let nix = require("nix")?;
|
||||||
let nix_channel = require("nix-channel")?;
|
let nix_channel = require("nix-channel")?;
|
||||||
let nix_env = require("nix-env")?;
|
let nix_env = require("nix-env")?;
|
||||||
// TODO: Is None possible here?
|
// TODO: Is None possible here? Should we use HOME_DIR instead?
|
||||||
let profile_path = match home::home_dir() {
|
let profile_path = match home_dir() {
|
||||||
Some(home) => XDG_DIRS
|
Some(home) => XDG_DIRS
|
||||||
.state_dir()
|
.state_dir()
|
||||||
.map(|d| d.join("nix/profile"))
|
.map(|d| d.join("nix/profile"))
|
||||||
@@ -824,7 +859,23 @@ pub fn run_mise(ctx: &ExecutionContext) -> Result<()> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ctx.execute(&mise).arg("upgrade").status_checked()
|
let mut cmd = ctx.execute(&mise);
|
||||||
|
|
||||||
|
cmd.arg("upgrade");
|
||||||
|
|
||||||
|
if ctx.config().mise_interactive() {
|
||||||
|
cmd.arg("--interactive");
|
||||||
|
}
|
||||||
|
|
||||||
|
if ctx.config().mise_bump() {
|
||||||
|
cmd.arg("--bump");
|
||||||
|
}
|
||||||
|
|
||||||
|
if ctx.config().mise_jobs() != 4 {
|
||||||
|
cmd.args(["--jobs", &ctx.config().mise_jobs().to_string()]);
|
||||||
|
}
|
||||||
|
|
||||||
|
cmd.status_checked()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn run_home_manager(ctx: &ExecutionContext) -> Result<()> {
|
pub fn run_home_manager(ctx: &ExecutionContext) -> Result<()> {
|
||||||
|
|||||||
@@ -254,11 +254,7 @@ pub fn microsoft_store(ctx: &ExecutionContext) -> Result<()> {
|
|||||||
}
|
}
|
||||||
let ret_val = output.stdout.trim();
|
let ret_val = output.stdout.trim();
|
||||||
debug!("Command return value: {}", ret_val);
|
debug!("Command return value: {}", ret_val);
|
||||||
if ret_val == "0" {
|
if ret_val == "0" { Ok(()) } else { Err(()) }
|
||||||
Ok(())
|
|
||||||
} else {
|
|
||||||
Err(())
|
|
||||||
}
|
|
||||||
})?;
|
})?;
|
||||||
println!(
|
println!(
|
||||||
"{}",
|
"{}",
|
||||||
|
|||||||
@@ -1,15 +1,15 @@
|
|||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
use std::process::Command;
|
use std::process::Command;
|
||||||
|
|
||||||
|
use color_eyre::eyre::Result;
|
||||||
#[cfg(windows)]
|
#[cfg(windows)]
|
||||||
use color_eyre::eyre::eyre;
|
use color_eyre::eyre::eyre;
|
||||||
use color_eyre::eyre::Result;
|
|
||||||
use tracing::debug;
|
use tracing::debug;
|
||||||
|
|
||||||
use crate::command::CommandExt;
|
use crate::command::CommandExt;
|
||||||
use crate::execution_context::ExecutionContext;
|
use crate::execution_context::ExecutionContext;
|
||||||
use crate::terminal;
|
use crate::terminal;
|
||||||
use crate::utils::{which, PathExt};
|
use crate::utils::{PathExt, which};
|
||||||
|
|
||||||
pub struct Powershell {
|
pub struct Powershell {
|
||||||
path: PathBuf,
|
path: PathBuf,
|
||||||
|
|||||||
@@ -2,20 +2,20 @@ use std::env;
|
|||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
use std::process::Command;
|
use std::process::Command;
|
||||||
|
|
||||||
use color_eyre::eyre::eyre;
|
|
||||||
use color_eyre::eyre::Context;
|
use color_eyre::eyre::Context;
|
||||||
use color_eyre::eyre::Result;
|
use color_eyre::eyre::Result;
|
||||||
|
use color_eyre::eyre::eyre;
|
||||||
use etcetera::base_strategy::BaseStrategy;
|
use etcetera::base_strategy::BaseStrategy;
|
||||||
|
|
||||||
use crate::command::CommandExt;
|
use crate::command::CommandExt;
|
||||||
use crate::config::TmuxConfig;
|
use crate::config::TmuxConfig;
|
||||||
use crate::config::TmuxSessionMode;
|
use crate::config::TmuxSessionMode;
|
||||||
use crate::terminal::print_separator;
|
use crate::terminal::print_separator;
|
||||||
|
use crate::{HOME_DIR, XDG_DIRS};
|
||||||
use crate::{
|
use crate::{
|
||||||
execution_context::ExecutionContext,
|
execution_context::ExecutionContext,
|
||||||
utils::{which, PathExt},
|
utils::{PathExt, which},
|
||||||
};
|
};
|
||||||
use crate::{HOME_DIR, XDG_DIRS};
|
|
||||||
|
|
||||||
use rust_i18n::t;
|
use rust_i18n::t;
|
||||||
#[cfg(unix)]
|
#[cfg(unix)]
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
|
use crate::HOME_DIR;
|
||||||
use crate::command::CommandExt;
|
use crate::command::CommandExt;
|
||||||
use crate::error::{SkipStep, TopgradeError};
|
use crate::error::{SkipStep, TopgradeError};
|
||||||
use crate::HOME_DIR;
|
|
||||||
use color_eyre::eyre::Result;
|
use color_eyre::eyre::Result;
|
||||||
use etcetera::base_strategy::BaseStrategy;
|
use etcetera::base_strategy::BaseStrategy;
|
||||||
|
|
||||||
@@ -8,7 +8,7 @@ use crate::executor::{Executor, ExecutorOutput};
|
|||||||
use crate::terminal::print_separator;
|
use crate::terminal::print_separator;
|
||||||
use crate::{
|
use crate::{
|
||||||
execution_context::ExecutionContext,
|
execution_context::ExecutionContext,
|
||||||
utils::{require, PathExt},
|
utils::{PathExt, require},
|
||||||
};
|
};
|
||||||
use rust_i18n::t;
|
use rust_i18n::t;
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
|
|||||||
@@ -6,13 +6,13 @@ use color_eyre::eyre::Result;
|
|||||||
use tracing::debug;
|
use tracing::debug;
|
||||||
use walkdir::WalkDir;
|
use walkdir::WalkDir;
|
||||||
|
|
||||||
|
use crate::HOME_DIR;
|
||||||
|
use crate::XDG_DIRS;
|
||||||
use crate::command::CommandExt;
|
use crate::command::CommandExt;
|
||||||
use crate::execution_context::ExecutionContext;
|
use crate::execution_context::ExecutionContext;
|
||||||
use crate::git::RepoStep;
|
use crate::git::RepoStep;
|
||||||
use crate::terminal::print_separator;
|
use crate::terminal::print_separator;
|
||||||
use crate::utils::{require, PathExt};
|
use crate::utils::{PathExt, require};
|
||||||
use crate::HOME_DIR;
|
|
||||||
use crate::XDG_DIRS;
|
|
||||||
use etcetera::base_strategy::BaseStrategy;
|
use etcetera::base_strategy::BaseStrategy;
|
||||||
|
|
||||||
pub fn run_zr(ctx: &ExecutionContext) -> Result<()> {
|
pub fn run_zr(ctx: &ExecutionContext) -> Result<()> {
|
||||||
@@ -162,7 +162,7 @@ pub fn run_oh_my_zsh(ctx: &ExecutionContext) -> Result<()> {
|
|||||||
if let Ok(output) = res_env_zsh {
|
if let Ok(output) = res_env_zsh {
|
||||||
let env_zsh = output.stdout;
|
let env_zsh = output.stdout;
|
||||||
debug!("Oh-my-zsh: under SSH, setting ZSH={}", env_zsh);
|
debug!("Oh-my-zsh: under SSH, setting ZSH={}", env_zsh);
|
||||||
env::set_var("ZSH", env_zsh);
|
unsafe { env::set_var("ZSH", env_zsh) };
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -4,10 +4,10 @@ use std::path::PathBuf;
|
|||||||
|
|
||||||
#[cfg(windows)]
|
#[cfg(windows)]
|
||||||
use color_eyre::eyre;
|
use color_eyre::eyre;
|
||||||
#[cfg(windows)]
|
|
||||||
use color_eyre::eyre::eyre;
|
|
||||||
use color_eyre::eyre::Context;
|
use color_eyre::eyre::Context;
|
||||||
use color_eyre::eyre::Result;
|
use color_eyre::eyre::Result;
|
||||||
|
#[cfg(windows)]
|
||||||
|
use color_eyre::eyre::eyre;
|
||||||
use rust_i18n::t;
|
use rust_i18n::t;
|
||||||
use serde::Deserialize;
|
use serde::Deserialize;
|
||||||
use strum::Display;
|
use strum::Display;
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ use std::time::Duration;
|
|||||||
use chrono::{Local, Timelike};
|
use chrono::{Local, Timelike};
|
||||||
use color_eyre::eyre;
|
use color_eyre::eyre;
|
||||||
use color_eyre::eyre::Context;
|
use color_eyre::eyre::Context;
|
||||||
use console::{style, Key, Term};
|
use console::{Key, Term, style};
|
||||||
use notify_rust::{Notification, Timeout};
|
use notify_rust::{Notification, Timeout};
|
||||||
use rust_i18n::t;
|
use rust_i18n::t;
|
||||||
use tracing::{debug, error};
|
use tracing::{debug, error};
|
||||||
@@ -201,10 +201,11 @@ impl Terminal {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[allow(unused_variables)]
|
#[allow(unused_variables)]
|
||||||
fn should_retry(&mut self, interrupted: bool, step_name: &str) -> eyre::Result<bool> {
|
fn should_retry(&mut self, step_name: &str) -> eyre::Result<ShouldRetry> {
|
||||||
if self.width.is_none() {
|
if self.width.is_none() {
|
||||||
return Ok(false);
|
return Ok(ShouldRetry::No);
|
||||||
}
|
}
|
||||||
|
|
||||||
if self.set_title {
|
if self.set_title {
|
||||||
@@ -223,7 +224,7 @@ impl Terminal {
|
|||||||
|
|
||||||
let answer = loop {
|
let answer = loop {
|
||||||
match self.term.read_key() {
|
match self.term.read_key() {
|
||||||
Ok(Key::Char('y' | 'Y')) => break Ok(true),
|
Ok(Key::Char('y' | 'Y')) => break Ok(ShouldRetry::Yes),
|
||||||
Ok(Key::Char('s' | 'S')) => {
|
Ok(Key::Char('s' | 'S')) => {
|
||||||
println!(
|
println!(
|
||||||
"\n\n{}\n",
|
"\n\n{}\n",
|
||||||
@@ -232,16 +233,16 @@ impl Terminal {
|
|||||||
if let Err(err) = run_shell().context("Failed to run shell") {
|
if let Err(err) = run_shell().context("Failed to run shell") {
|
||||||
self.term.write_fmt(format_args!("{err:?}\n{prompt_inner}")).ok();
|
self.term.write_fmt(format_args!("{err:?}\n{prompt_inner}")).ok();
|
||||||
} else {
|
} else {
|
||||||
break Ok(true);
|
break Ok(ShouldRetry::Yes);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Ok(Key::Char('n' | 'N') | Key::Enter) => break Ok(false),
|
Ok(Key::Char('n' | 'N') | Key::Enter) => break Ok(ShouldRetry::No),
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
error!("Error reading from terminal: {}", e);
|
error!("Error reading from terminal: {}", e);
|
||||||
break Ok(false);
|
break Ok(ShouldRetry::No);
|
||||||
}
|
}
|
||||||
Ok(Key::Char('q' | 'Q')) => {
|
Ok(Key::Char('q' | 'Q')) => {
|
||||||
return Err(io::Error::from(io::ErrorKind::Interrupted)).context("Quit from user input")
|
break Ok(ShouldRetry::Quit);
|
||||||
}
|
}
|
||||||
_ => (),
|
_ => (),
|
||||||
}
|
}
|
||||||
@@ -257,14 +258,21 @@ impl Terminal {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Copy)]
|
||||||
|
pub enum ShouldRetry {
|
||||||
|
Yes,
|
||||||
|
No,
|
||||||
|
Quit,
|
||||||
|
}
|
||||||
|
|
||||||
impl Default for Terminal {
|
impl Default for Terminal {
|
||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
Self::new()
|
Self::new()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn should_retry(interrupted: bool, step_name: &str) -> eyre::Result<bool> {
|
pub fn should_retry(step_name: &str) -> eyre::Result<ShouldRetry> {
|
||||||
TERMINAL.lock().unwrap().should_retry(interrupted, step_name)
|
TERMINAL.lock().unwrap().should_retry(step_name)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn print_separator<P: AsRef<str>>(message: P) {
|
pub fn print_separator<P: AsRef<str>>(message: P) {
|
||||||
|
|||||||
@@ -11,8 +11,8 @@ use tracing::{debug, error};
|
|||||||
use tracing_subscriber::layer::SubscriberExt;
|
use tracing_subscriber::layer::SubscriberExt;
|
||||||
use tracing_subscriber::reload::{Handle, Layer};
|
use tracing_subscriber::reload::{Handle, Layer};
|
||||||
use tracing_subscriber::util::SubscriberInitExt;
|
use tracing_subscriber::util::SubscriberInitExt;
|
||||||
use tracing_subscriber::{fmt, Registry};
|
use tracing_subscriber::{EnvFilter, registry};
|
||||||
use tracing_subscriber::{registry, EnvFilter};
|
use tracing_subscriber::{Registry, fmt};
|
||||||
|
|
||||||
use crate::command::CommandExt;
|
use crate::command::CommandExt;
|
||||||
use crate::config::DEFAULT_LOG_LEVEL;
|
use crate::config::DEFAULT_LOG_LEVEL;
|
||||||
@@ -218,7 +218,7 @@ pub mod merge_strategies {
|
|||||||
where
|
where
|
||||||
T: Merge,
|
T: Merge,
|
||||||
{
|
{
|
||||||
if let Some(ref mut left_inner) = left {
|
if let Some(left_inner) = left {
|
||||||
if let Some(right_inner) = right {
|
if let Some(right_inner) = right {
|
||||||
left_inner.merge(right_inner);
|
left_inner.merge(right_inner);
|
||||||
}
|
}
|
||||||
@@ -228,7 +228,7 @@ pub mod merge_strategies {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn commands_merge_opt(left: &mut Option<Commands>, right: Option<Commands>) {
|
pub fn commands_merge_opt(left: &mut Option<Commands>, right: Option<Commands>) {
|
||||||
if let Some(ref mut left_inner) = left {
|
if let Some(left_inner) = left {
|
||||||
if let Some(right_inner) = right {
|
if let Some(right_inner) = right {
|
||||||
left_inner.extend(right_inner);
|
left_inner.extend(right_inner);
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user