Compare commits
63 Commits
v10.1.0-cd
...
v10.2.1
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
96e4de4594 | ||
|
|
70616b2ec5 | ||
|
|
22ab07d88e | ||
|
|
70045fca29 | ||
|
|
f6ec6c76db | ||
|
|
37b900c56a | ||
|
|
e26ec4d9e0 | ||
|
|
b31778bdd8 | ||
|
|
526c4c9a58 | ||
|
|
3c1dda0c39 | ||
|
|
25c5057171 | ||
|
|
e456155562 | ||
|
|
f2c7e4848e | ||
|
|
b4407963ad | ||
|
|
85a4691229 | ||
|
|
8e9c3cc56a | ||
|
|
7cdaefe3b0 | ||
|
|
aedb25cde6 | ||
|
|
582bc737cb | ||
|
|
c4091584c3 | ||
|
|
22ed1ef50a | ||
|
|
41e2321b93 | ||
|
|
d8add139e1 | ||
|
|
04a8d960a9 | ||
|
|
2c6a8f73fa | ||
|
|
71883d7164 | ||
|
|
d4fe748814 | ||
|
|
369d923532 | ||
|
|
6be4a4a48d | ||
|
|
7442ddd386 | ||
|
|
761ffac127 | ||
|
|
5ca1dc3703 | ||
|
|
a18c6e815c | ||
|
|
022afab1ca | ||
|
|
2cbb7db66d | ||
|
|
e84173be8f | ||
|
|
bd34a3bcd4 | ||
|
|
13076fcef6 | ||
|
|
6f48017761 | ||
|
|
7fb07879bb | ||
|
|
ecbaf52156 | ||
|
|
6a6a84b0c5 | ||
|
|
3486200b2c | ||
|
|
f6b3a8fdca | ||
|
|
058a6fd9c9 | ||
|
|
e1783e3af8 | ||
|
|
e161d3cd3c | ||
|
|
318f935b43 | ||
|
|
3dc245245d | ||
|
|
9de111aa0f | ||
|
|
18951c8447 | ||
|
|
b6e50a38af | ||
|
|
8acdfc8d1c | ||
|
|
a6da5181f2 | ||
|
|
60ff087048 | ||
|
|
3ebaac3a1d | ||
|
|
e4f8488837 | ||
|
|
d8748b004b | ||
|
|
2a11df40ee | ||
|
|
16953409fd | ||
|
|
c85adb8980 | ||
|
|
0f0cbc1453 | ||
|
|
91554cac56 |
121
.github/workflows/check-and-lint.yaml
vendored
121
.github/workflows/check-and-lint.yaml
vendored
@@ -4,63 +4,88 @@ on:
|
|||||||
branches:
|
branches:
|
||||||
- main
|
- main
|
||||||
|
|
||||||
|
name: CI
|
||||||
|
|
||||||
name: Check and Lint
|
env:
|
||||||
|
RUST_VER: '1.60.0'
|
||||||
|
CROSS_VER: '0.2.4'
|
||||||
|
CARGO_NET_RETRY: 3
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
check:
|
|
||||||
name: Check
|
|
||||||
matrix:
|
|
||||||
platform: [ ubuntu-latest, macos-latest, windows-latest ]
|
|
||||||
runs-on: ${{ matrix.platform }}
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@v2
|
|
||||||
- uses: actions-rs/toolchain@v1
|
|
||||||
with:
|
|
||||||
profile: minimal
|
|
||||||
toolchain: stable
|
|
||||||
override: true
|
|
||||||
- uses: actions-rs/cargo@v1
|
|
||||||
with:
|
|
||||||
command: check
|
|
||||||
|
|
||||||
fmt:
|
fmt:
|
||||||
name: Rustfmt
|
name: Rustfmt
|
||||||
matrix:
|
runs-on: ubuntu-20.04
|
||||||
platform: [ ubuntu-latest, macos-latest, windows-latest ]
|
|
||||||
runs-on: ${{ matrix.platform }}
|
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v2
|
- name: Checkout code
|
||||||
- uses: actions-rs/toolchain@v1
|
uses: actions/checkout@v3
|
||||||
with:
|
|
||||||
profile: minimal
|
|
||||||
toolchain: stable
|
|
||||||
override: true
|
|
||||||
- run: rustup component add rustfmt
|
|
||||||
- uses: actions-rs/cargo@v1
|
|
||||||
with:
|
|
||||||
command: fmt
|
|
||||||
args: --all -- --check
|
|
||||||
|
|
||||||
clippy:
|
- name: Setup Rust
|
||||||
name: Clippy
|
uses: dtolnay/rust-toolchain@master
|
||||||
|
with:
|
||||||
|
toolchain: '${{ env.RUST_VER }}'
|
||||||
|
components: rustfmt
|
||||||
|
|
||||||
|
- name: Run cargo fmt
|
||||||
|
env:
|
||||||
|
TERM: xterm-256color
|
||||||
|
run: |
|
||||||
|
cargo fmt --all -- --check
|
||||||
|
|
||||||
|
main:
|
||||||
|
needs: fmt
|
||||||
|
name: ${{ matrix.target_name }} (check, clippy)
|
||||||
|
runs-on: ${{ matrix.os }}
|
||||||
|
strategy:
|
||||||
|
fail-fast: false
|
||||||
matrix:
|
matrix:
|
||||||
platform: [ ubuntu-latest, macos-latest, windows-latest ]
|
include:
|
||||||
runs-on: ${{ matrix.platform }}
|
- target: x86_64-linux-android
|
||||||
|
target_name: Android
|
||||||
|
use_cross: true
|
||||||
|
os: ubuntu-20.04
|
||||||
|
|
||||||
|
- target: x86_64-unknown-freebsd
|
||||||
|
target_name: FreeBSD
|
||||||
|
use_cross: true
|
||||||
|
os: ubuntu-20.04
|
||||||
|
|
||||||
|
- target: x86_64-unknown-linux-gnu
|
||||||
|
target_name: Linux
|
||||||
|
os: ubuntu-20.04
|
||||||
|
|
||||||
|
- target: x86_64-apple-darwin
|
||||||
|
target_name: macOS
|
||||||
|
os: macos-11
|
||||||
|
|
||||||
|
- target: x86_64-unknown-netbsd
|
||||||
|
target_name: NetBSD
|
||||||
|
use_cross: true
|
||||||
|
os: ubuntu-20.04
|
||||||
|
|
||||||
|
- target: x86_64-pc-windows-msvc
|
||||||
|
target_name: Windows
|
||||||
|
os: windows-2019
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v2
|
- name: Checkout code
|
||||||
- uses: actions-rs/toolchain@v1
|
uses: actions/checkout@v3
|
||||||
|
|
||||||
|
- name: Setup Rust
|
||||||
|
uses: dtolnay/rust-toolchain@master
|
||||||
with:
|
with:
|
||||||
toolchain: stable
|
toolchain: '${{ env.RUST_VER }}'
|
||||||
components: clippy
|
components: clippy
|
||||||
override: true
|
|
||||||
- uses: actions-rs/clippy-check@v1
|
- name: Setup Rust Cache
|
||||||
|
uses: Swatinem/rust-cache@v2
|
||||||
with:
|
with:
|
||||||
token: ${{ secrets.GITHUB_TOKEN }}
|
prefix-key: ${{ matrix.target }}
|
||||||
args: --all-targets --locked -- -D warnings
|
|
||||||
name: Clippy Output
|
- name: Setup cross
|
||||||
- uses: actions-rs/clippy-check@v1
|
if: matrix.use_cross == true
|
||||||
with:
|
run: curl -fL --retry 3 https://github.com/cross-rs/cross/releases/download/v${{ env.CROSS_VER }}/cross-x86_64-unknown-linux-musl.tar.gz | tar vxz -C /usr/local/bin
|
||||||
token: ${{ secrets.GITHUB_TOKEN }}
|
|
||||||
args: --all-targets --locked --all-features -- -D warnings
|
- name: Run cargo check
|
||||||
name: Clippy (All features) Output
|
run: ${{ matrix.use_cross == true && 'cross' || 'cargo' }} check --locked --target ${{ matrix.target }}
|
||||||
|
|
||||||
|
- name: Run cargo clippy
|
||||||
|
run: ${{ matrix.use_cross == true && 'cross' || 'cargo' }} clippy --locked --target ${{ matrix.target }} --all-features -- -D warnings
|
||||||
|
|||||||
38
.github/workflows/update_homebrew.yml
vendored
Normal file
38
.github/workflows/update_homebrew.yml
vendored
Normal file
@@ -0,0 +1,38 @@
|
|||||||
|
name: Publish to Homebrew
|
||||||
|
|
||||||
|
on:
|
||||||
|
# workflow_run:
|
||||||
|
# workflows: ["Check SemVer compliance"]
|
||||||
|
# types:
|
||||||
|
# - completed
|
||||||
|
workflow_dispatch:
|
||||||
|
push:
|
||||||
|
tags:
|
||||||
|
- "v*"
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
homebrew-publish:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- name: Set up Homebrew
|
||||||
|
id: set-up-homebrew
|
||||||
|
uses: Homebrew/actions/setup-homebrew@master
|
||||||
|
- name: Cache Homebrew Bundler RubyGems
|
||||||
|
id: cache
|
||||||
|
uses: actions/cache@v1
|
||||||
|
with:
|
||||||
|
path: ${{ steps.set-up-homebrew.outputs.gems-path }}
|
||||||
|
key: ${{ runner.os }}-rubygems-${{ steps.set-up-homebrew.outputs.gems-hash }}
|
||||||
|
restore-keys: ${{ runner.os }}-rubygems-
|
||||||
|
|
||||||
|
- name: Install Homebrew Bundler RubyGems
|
||||||
|
if: steps.cache.outputs.cache-hit != 'true'
|
||||||
|
run: brew install-bundler-gems
|
||||||
|
- name: Bump formulae
|
||||||
|
uses: Homebrew/actions/bump-formulae@master
|
||||||
|
with:
|
||||||
|
# Custom GitHub access token with only the 'public_repo' scope enabled
|
||||||
|
token: ${{secrets.HOMEBREW_ACCESS_TOKEN}}
|
||||||
|
# Bump only these formulae if outdated
|
||||||
|
formulae: |
|
||||||
|
topgrade
|
||||||
128
CODE_OF_CONDUCT.md
Normal file
128
CODE_OF_CONDUCT.md
Normal file
@@ -0,0 +1,128 @@
|
|||||||
|
# Contributor Covenant Code of Conduct
|
||||||
|
|
||||||
|
## Our Pledge
|
||||||
|
|
||||||
|
We as members, contributors, and leaders pledge to make participation in our
|
||||||
|
community a harassment-free experience for everyone, regardless of age, body
|
||||||
|
size, visible or invisible disability, ethnicity, sex characteristics, gender
|
||||||
|
identity and expression, level of experience, education, socio-economic status,
|
||||||
|
nationality, personal appearance, race, religion, or sexual identity
|
||||||
|
and orientation.
|
||||||
|
|
||||||
|
We pledge to act and interact in ways that contribute to an open, welcoming,
|
||||||
|
diverse, inclusive, and healthy community.
|
||||||
|
|
||||||
|
## Our Standards
|
||||||
|
|
||||||
|
Examples of behavior that contributes to a positive environment for our
|
||||||
|
community include:
|
||||||
|
|
||||||
|
* Demonstrating empathy and kindness toward other people
|
||||||
|
* Being respectful of differing opinions, viewpoints, and experiences
|
||||||
|
* Giving and gracefully accepting constructive feedback
|
||||||
|
* Accepting responsibility and apologizing to those affected by our mistakes,
|
||||||
|
and learning from the experience
|
||||||
|
* Focusing on what is best not just for us as individuals, but for the
|
||||||
|
overall community
|
||||||
|
|
||||||
|
Examples of unacceptable behavior include:
|
||||||
|
|
||||||
|
* The use of sexualized language or imagery, and sexual attention or
|
||||||
|
advances of any kind
|
||||||
|
* Trolling, insulting or derogatory comments, and personal or political attacks
|
||||||
|
* Public or private harassment
|
||||||
|
* Publishing others' private information, such as a physical or email
|
||||||
|
address, without their explicit permission
|
||||||
|
* Other conduct which could reasonably be considered inappropriate in a
|
||||||
|
professional setting
|
||||||
|
|
||||||
|
## Enforcement Responsibilities
|
||||||
|
|
||||||
|
Community leaders are responsible for clarifying and enforcing our standards of
|
||||||
|
acceptable behavior and will take appropriate and fair corrective action in
|
||||||
|
response to any behavior that they deem inappropriate, threatening, offensive,
|
||||||
|
or harmful.
|
||||||
|
|
||||||
|
Community leaders have the right and responsibility to remove, edit, or reject
|
||||||
|
comments, commits, code, wiki edits, issues, and other contributions that are
|
||||||
|
not aligned to this Code of Conduct, and will communicate reasons for moderation
|
||||||
|
decisions when appropriate.
|
||||||
|
|
||||||
|
## Scope
|
||||||
|
|
||||||
|
This Code of Conduct applies within all community spaces, and also applies when
|
||||||
|
an individual is officially representing the community in public spaces.
|
||||||
|
Examples of representing our community include using an official e-mail address,
|
||||||
|
posting via an official social media account, or acting as an appointed
|
||||||
|
representative at an online or offline event.
|
||||||
|
|
||||||
|
## Enforcement
|
||||||
|
|
||||||
|
Instances of abusive, harassing, or otherwise unacceptable behavior may be
|
||||||
|
reported to the community leaders responsible for enforcement at
|
||||||
|
open an issue on GitHub .
|
||||||
|
All complaints will be reviewed and investigated promptly and fairly.
|
||||||
|
|
||||||
|
All community leaders are obligated to respect the privacy and security of the
|
||||||
|
reporter of any incident.
|
||||||
|
|
||||||
|
## Enforcement Guidelines
|
||||||
|
|
||||||
|
Community leaders will follow these Community Impact Guidelines in determining
|
||||||
|
the consequences for any action they deem in violation of this Code of Conduct:
|
||||||
|
|
||||||
|
### 1. Correction
|
||||||
|
|
||||||
|
**Community Impact**: Use of inappropriate language or other behavior deemed
|
||||||
|
unprofessional or unwelcome in the community.
|
||||||
|
|
||||||
|
**Consequence**: A private, written warning from community leaders, providing
|
||||||
|
clarity around the nature of the violation and an explanation of why the
|
||||||
|
behavior was inappropriate. A public apology may be requested.
|
||||||
|
|
||||||
|
### 2. Warning
|
||||||
|
|
||||||
|
**Community Impact**: A violation through a single incident or series
|
||||||
|
of actions.
|
||||||
|
|
||||||
|
**Consequence**: A warning with consequences for continued behavior. No
|
||||||
|
interaction with the people involved, including unsolicited interaction with
|
||||||
|
those enforcing the Code of Conduct, for a specified period of time. This
|
||||||
|
includes avoiding interactions in community spaces as well as external channels
|
||||||
|
like social media. Violating these terms may lead to a temporary or
|
||||||
|
permanent ban.
|
||||||
|
|
||||||
|
### 3. Temporary Ban
|
||||||
|
|
||||||
|
**Community Impact**: A serious violation of community standards, including
|
||||||
|
sustained inappropriate behavior.
|
||||||
|
|
||||||
|
**Consequence**: A temporary ban from any sort of interaction or public
|
||||||
|
communication with the community for a specified period of time. No public or
|
||||||
|
private interaction with the people involved, including unsolicited interaction
|
||||||
|
with those enforcing the Code of Conduct, is allowed during this period.
|
||||||
|
Violating these terms may lead to a permanent ban.
|
||||||
|
|
||||||
|
### 4. Permanent Ban
|
||||||
|
|
||||||
|
**Community Impact**: Demonstrating a pattern of violation of community
|
||||||
|
standards, including sustained inappropriate behavior, harassment of an
|
||||||
|
individual, or aggression toward or disparagement of classes of individuals.
|
||||||
|
|
||||||
|
**Consequence**: A permanent ban from any sort of public interaction within
|
||||||
|
the community.
|
||||||
|
|
||||||
|
## Attribution
|
||||||
|
|
||||||
|
This Code of Conduct is adapted from the [Contributor Covenant][homepage],
|
||||||
|
version 2.0, available at
|
||||||
|
https://www.contributor-covenant.org/version/2/0/code_of_conduct.html.
|
||||||
|
|
||||||
|
Community Impact Guidelines were inspired by [Mozilla's code of conduct
|
||||||
|
enforcement ladder](https://github.com/mozilla/diversity).
|
||||||
|
|
||||||
|
[homepage]: https://www.contributor-covenant.org
|
||||||
|
|
||||||
|
For answers to common questions about this code of conduct, see the FAQ at
|
||||||
|
https://www.contributor-covenant.org/faq. Translations are available at
|
||||||
|
https://www.contributor-covenant.org/translations.
|
||||||
483
Cargo.lock
generated
483
Cargo.lock
generated
@@ -2,6 +2,15 @@
|
|||||||
# It is not intended for manual editing.
|
# It is not intended for manual editing.
|
||||||
version = 3
|
version = 3
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "addr2line"
|
||||||
|
version = "0.17.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "b9ecd88a8c8378ca913a680cd98f0f13ac67383d35993f86c90a70e3f137816b"
|
||||||
|
dependencies = [
|
||||||
|
"gimli",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "adler"
|
name = "adler"
|
||||||
version = "1.0.2"
|
version = "1.0.2"
|
||||||
@@ -21,9 +30,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "aho-corasick"
|
name = "aho-corasick"
|
||||||
version = "0.7.19"
|
version = "0.7.20"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "b4f55bd91a0978cbfd91c457a164bab8b4001c833b7f323132c0a4e1922dd44e"
|
checksum = "cc936419f96fa211c1b9166887b38e5e40b19958e5b895be7c1f93adec7071ac"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"memchr",
|
"memchr",
|
||||||
]
|
]
|
||||||
@@ -37,12 +46,6 @@ dependencies = [
|
|||||||
"libc",
|
"libc",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "anyhow"
|
|
||||||
version = "1.0.66"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "216261ddc8289130e551ddcd5ce8a064710c0d064a4d2895c67151c92b5443f6"
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "async-broadcast"
|
name = "async-broadcast"
|
||||||
version = "0.4.1"
|
version = "0.4.1"
|
||||||
@@ -56,9 +59,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "async-channel"
|
name = "async-channel"
|
||||||
version = "1.7.1"
|
version = "1.8.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "e14485364214912d3b19cc3435dde4df66065127f05fa0d75c712f36f12c2f28"
|
checksum = "cf46fee83e5ccffc220104713af3292ff9bc7c64c7de289f66dae8e38d826833"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"concurrent-queue",
|
"concurrent-queue",
|
||||||
"event-listener",
|
"event-listener",
|
||||||
@@ -67,23 +70,23 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "async-executor"
|
name = "async-executor"
|
||||||
version = "1.4.1"
|
version = "1.5.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "871f9bb5e0a22eeb7e8cf16641feb87c9dc67032ccf8ff49e772eb9941d3a965"
|
checksum = "17adb73da160dfb475c183343c8cccd80721ea5a605d3eb57125f0a7b7a92d0b"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
|
"async-lock",
|
||||||
"async-task",
|
"async-task",
|
||||||
"concurrent-queue",
|
"concurrent-queue",
|
||||||
"fastrand",
|
"fastrand",
|
||||||
"futures-lite",
|
"futures-lite",
|
||||||
"once_cell",
|
|
||||||
"slab",
|
"slab",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "async-io"
|
name = "async-io"
|
||||||
version = "1.10.0"
|
version = "1.12.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "e8121296a9f05be7f34aa4196b1747243b3b62e048bb7906f644f3fbfc490cf7"
|
checksum = "8c374dda1ed3e7d8f0d9ba58715f924862c63eae6849c92d3a18e7fbde9e2794"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"async-lock",
|
"async-lock",
|
||||||
"autocfg",
|
"autocfg",
|
||||||
@@ -96,7 +99,7 @@ dependencies = [
|
|||||||
"slab",
|
"slab",
|
||||||
"socket2",
|
"socket2",
|
||||||
"waker-fn",
|
"waker-fn",
|
||||||
"winapi",
|
"windows-sys",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -128,9 +131,9 @@ checksum = "7a40729d2133846d9ed0ea60a8b9541bccddab49cd30f0715a1da672fe9a2524"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "async-trait"
|
name = "async-trait"
|
||||||
version = "0.1.58"
|
version = "0.1.59"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "1e805d94e6b5001b651426cf4cd446b1ab5f319d27bab5c644f61de0a804360c"
|
checksum = "31e6e93155431f3931513b243d371981bb2770112b370c82745a1d19d2f99364"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
@@ -154,6 +157,21 @@ version = "1.1.0"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa"
|
checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "backtrace"
|
||||||
|
version = "0.3.66"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "cab84319d616cfb654d03394f38ab7e6f0919e181b1b57e1fd15e7fb4077d9a7"
|
||||||
|
dependencies = [
|
||||||
|
"addr2line",
|
||||||
|
"cc",
|
||||||
|
"cfg-if",
|
||||||
|
"libc",
|
||||||
|
"miniz_oxide 0.5.4",
|
||||||
|
"object",
|
||||||
|
"rustc-demangle",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "base64"
|
name = "base64"
|
||||||
version = "0.13.1"
|
version = "0.13.1"
|
||||||
@@ -186,21 +204,15 @@ checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "bytes"
|
name = "bytes"
|
||||||
version = "1.2.1"
|
version = "1.3.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "ec8a7b6a70fde80372154c65702f00a0f56f3e1c36abbc6c440484be248856db"
|
checksum = "dfb24e866b15a1af2a1b663f10c6b6b8f397a84aadb828f12e5b289ec23a3a3c"
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "cache-padded"
|
|
||||||
version = "1.2.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "c1db59621ec70f09c5e9b597b220c7a2b43611f4710dc03ceb8748637775692c"
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "cc"
|
name = "cc"
|
||||||
version = "1.0.74"
|
version = "1.0.77"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "581f5dba903aac52ea3feb5ec4810848460ee833876f1f9b0fdeab1f19091574"
|
checksum = "e9f73505338f7d905b19d18738976aae232eb46b8efc15554ffc56deb5d9ebe4"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "cfg-if"
|
name = "cfg-if"
|
||||||
@@ -210,15 +222,15 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "chrono"
|
name = "chrono"
|
||||||
version = "0.4.22"
|
version = "0.4.23"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "bfd4d1b31faaa3a89d7934dbded3111da0d2ef28e3ebccdb4f0179f5929d1ef1"
|
checksum = "16b0a3d9ed01224b22057780a37bb8c5dbfe1be8ba48678e7bf57ec4b385411f"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"iana-time-zone",
|
"iana-time-zone",
|
||||||
"js-sys",
|
"js-sys",
|
||||||
"num-integer",
|
"num-integer",
|
||||||
"num-traits",
|
"num-traits",
|
||||||
"time 0.1.44",
|
"time 0.1.45",
|
||||||
"wasm-bindgen",
|
"wasm-bindgen",
|
||||||
"winapi",
|
"winapi",
|
||||||
]
|
]
|
||||||
@@ -240,6 +252,15 @@ dependencies = [
|
|||||||
"textwrap",
|
"textwrap",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "clap_complete"
|
||||||
|
version = "3.1.4"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "da92e6facd8d73c22745a5d3cbb59bdf8e46e3235c923e516527d8e81eec14a4"
|
||||||
|
dependencies = [
|
||||||
|
"clap",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "clap_derive"
|
name = "clap_derive"
|
||||||
version = "3.1.18"
|
version = "3.1.18"
|
||||||
@@ -262,6 +283,16 @@ dependencies = [
|
|||||||
"os_str_bytes",
|
"os_str_bytes",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "clap_mangen"
|
||||||
|
version = "0.1.7"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "121b598d1b9d63d4ff3b7dae8defd88cc23e41850ee89fd2feec2e7d992e6ec8"
|
||||||
|
dependencies = [
|
||||||
|
"clap",
|
||||||
|
"roff",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "codespan-reporting"
|
name = "codespan-reporting"
|
||||||
version = "0.11.1"
|
version = "0.11.1"
|
||||||
@@ -273,12 +304,39 @@ dependencies = [
|
|||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "concurrent-queue"
|
name = "color-eyre"
|
||||||
version = "1.2.4"
|
version = "0.6.2"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "af4780a44ab5696ea9e28294517f1fffb421a83a25af521333c838635509db9c"
|
checksum = "5a667583cca8c4f8436db8de46ea8233c42a7d9ae424a82d338f2e4675229204"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"cache-padded",
|
"backtrace",
|
||||||
|
"color-spantrace",
|
||||||
|
"eyre",
|
||||||
|
"indenter",
|
||||||
|
"once_cell",
|
||||||
|
"owo-colors",
|
||||||
|
"tracing-error",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "color-spantrace"
|
||||||
|
version = "0.2.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "1ba75b3d9449ecdccb27ecbc479fdc0b87fa2dd43d2f8298f9bf0e59aacc8dce"
|
||||||
|
dependencies = [
|
||||||
|
"once_cell",
|
||||||
|
"owo-colors",
|
||||||
|
"tracing-core",
|
||||||
|
"tracing-error",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "concurrent-queue"
|
||||||
|
version = "2.0.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "bd7bef69dc86e3c610e4e7aed41035e2a7ed12e72dd7530f61327a6579a4390b"
|
||||||
|
dependencies = [
|
||||||
|
"crossbeam-utils",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -312,18 +370,18 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "crossbeam-utils"
|
name = "crossbeam-utils"
|
||||||
version = "0.8.12"
|
version = "0.8.14"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "edbafec5fa1f196ca66527c1b12c2ec4745ca14b50f1ad8f9f6f720b55d11fac"
|
checksum = "4fb766fa798726286dbbb842f174001dab8abc7b627a1dd86e0b7222a95d929f"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"cfg-if",
|
"cfg-if",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "cxx"
|
name = "cxx"
|
||||||
version = "1.0.80"
|
version = "1.0.82"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "6b7d4e43b25d3c994662706a1d4fcfc32aaa6afd287502c111b237093bb23f3a"
|
checksum = "d4a41a86530d0fe7f5d9ea779916b7cadd2d4f9add748b99c2c029cbbdfaf453"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"cc",
|
"cc",
|
||||||
"cxxbridge-flags",
|
"cxxbridge-flags",
|
||||||
@@ -333,9 +391,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "cxx-build"
|
name = "cxx-build"
|
||||||
version = "1.0.80"
|
version = "1.0.82"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "84f8829ddc213e2c1368e51a2564c552b65a8cb6a28f31e576270ac81d5e5827"
|
checksum = "06416d667ff3e3ad2df1cd8cd8afae5da26cf9cec4d0825040f88b5ca659a2f0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"cc",
|
"cc",
|
||||||
"codespan-reporting",
|
"codespan-reporting",
|
||||||
@@ -348,15 +406,15 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "cxxbridge-flags"
|
name = "cxxbridge-flags"
|
||||||
version = "1.0.80"
|
version = "1.0.82"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "e72537424b474af1460806647c41d4b6d35d09ef7fe031c5c2fa5766047cc56a"
|
checksum = "820a9a2af1669deeef27cb271f476ffd196a2c4b6731336011e0ba63e2c7cf71"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "cxxbridge-macro"
|
name = "cxxbridge-macro"
|
||||||
version = "1.0.80"
|
version = "1.0.82"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "309e4fb93eed90e1e14bea0da16b209f81813ba9fc7830c20ed151dd7bc0a4d7"
|
checksum = "a08a6e2fcc370a089ad3b4aaf54db3b1b4cee38ddabce5896b33eb693275f470"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
@@ -472,25 +530,22 @@ dependencies = [
|
|||||||
"syn",
|
"syn",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "env_logger"
|
|
||||||
version = "0.7.1"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "44533bbbb3bb3c1fa17d9f2e4e38bbbaf8396ba82193c4cb1b6445d711445d36"
|
|
||||||
dependencies = [
|
|
||||||
"atty",
|
|
||||||
"humantime",
|
|
||||||
"log",
|
|
||||||
"regex",
|
|
||||||
"termcolor",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "event-listener"
|
name = "event-listener"
|
||||||
version = "2.5.3"
|
version = "2.5.3"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "0206175f82b8d6bf6652ff7d71a1e27fd2e4efde587fd368662814d6ec1d9ce0"
|
checksum = "0206175f82b8d6bf6652ff7d71a1e27fd2e4efde587fd368662814d6ec1d9ce0"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "eyre"
|
||||||
|
version = "0.6.8"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "4c2b6b5a29c02cdc822728b7d7b8ae1bab3e3b05d44522770ddd49722eeac7eb"
|
||||||
|
dependencies = [
|
||||||
|
"indenter",
|
||||||
|
"once_cell",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "fastrand"
|
name = "fastrand"
|
||||||
version = "1.8.0"
|
version = "1.8.0"
|
||||||
@@ -514,12 +569,12 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "flate2"
|
name = "flate2"
|
||||||
version = "1.0.24"
|
version = "1.0.25"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "f82b0f4c27ad9f8bfd1f3208d882da2b09c301bc1c828fd3a00d0216d2fbbff6"
|
checksum = "a8a2db397cb1c8772f31494cb8917e48cd1e64f0fa7efac59fbd741a0a8ce841"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"crc32fast",
|
"crc32fast",
|
||||||
"miniz_oxide",
|
"miniz_oxide 0.6.2",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -652,6 +707,12 @@ dependencies = [
|
|||||||
"wasi 0.11.0+wasi-snapshot-preview1",
|
"wasi 0.11.0+wasi-snapshot-preview1",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "gimli"
|
||||||
|
version = "0.26.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "22030e2c5a68ec659fde1e949a745124b48e6fa8b045b7ed5bd1fe4ccc5c4e5d"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "glob"
|
name = "glob"
|
||||||
version = "0.3.0"
|
version = "0.3.0"
|
||||||
@@ -759,20 +820,11 @@ version = "1.0.2"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "c4a1e36c821dbe04574f602848a19f742f4fb3c98d40449f11bcad18d6b17421"
|
checksum = "c4a1e36c821dbe04574f602848a19f742f4fb3c98d40449f11bcad18d6b17421"
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "humantime"
|
|
||||||
version = "1.3.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "df004cfca50ef23c36850aaaa59ad52cc70d0e90243c3c7737a4dd32dc7a3c4f"
|
|
||||||
dependencies = [
|
|
||||||
"quick-error",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "hyper"
|
name = "hyper"
|
||||||
version = "0.14.22"
|
version = "0.14.23"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "abfba89e19b959ca163c7752ba59d737c1ceea53a5d31a149c805446fc958064"
|
checksum = "034711faac9d2166cb1baf1a2fb0b60b1f277f8492fd72176c17f3515e1abd3c"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bytes",
|
"bytes",
|
||||||
"futures-channel",
|
"futures-channel",
|
||||||
@@ -794,9 +846,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "hyper-rustls"
|
name = "hyper-rustls"
|
||||||
version = "0.23.0"
|
version = "0.23.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "d87c48c02e0dc5e3b849a2041db3029fd066650f8f717c07bf8ed78ccb895cac"
|
checksum = "59df7c4e19c950e6e0e868dcc0a300b09a9b88e9ec55bd879ca819087a77355d"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"http",
|
"http",
|
||||||
"hyper",
|
"hyper",
|
||||||
@@ -840,10 +892,16 @@ dependencies = [
|
|||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "indexmap"
|
name = "indenter"
|
||||||
version = "1.9.1"
|
version = "0.3.3"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "10a35a97730320ffe8e2d410b5d3b69279b98d2c14bdb8b70ea89ecf7888d41e"
|
checksum = "ce23b50ad8242c51a442f3ff322d56b02f08852c77e4c0b4d3fd684abc89c683"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "indexmap"
|
||||||
|
version = "1.9.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "1885e79c1fc4b10f0e172c475f458b7f7b93061064d98c3293e98c5ba0c8b399"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"autocfg",
|
"autocfg",
|
||||||
"hashbrown",
|
"hashbrown",
|
||||||
@@ -872,9 +930,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "ipnet"
|
name = "ipnet"
|
||||||
version = "2.5.0"
|
version = "2.5.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "879d54834c8c76457ef4293a689b2a8c59b076067ad77b15efafbb05f92a592b"
|
checksum = "f88c5561171189e69df9d98bcf18fd5f9558300f7ea7b801eb8a0fd748bd8745"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "itoa"
|
name = "itoa"
|
||||||
@@ -941,7 +999,7 @@ dependencies = [
|
|||||||
"dirs-next",
|
"dirs-next",
|
||||||
"objc-foundation",
|
"objc-foundation",
|
||||||
"objc_id",
|
"objc_id",
|
||||||
"time 0.3.16",
|
"time 0.3.17",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -953,6 +1011,15 @@ dependencies = [
|
|||||||
"libc",
|
"libc",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "matchers"
|
||||||
|
version = "0.1.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "8263075bb86c5a1b1427b5ae862e8889656f126e9f77c484496e8b47cf5c5558"
|
||||||
|
dependencies = [
|
||||||
|
"regex-automata",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "memchr"
|
name = "memchr"
|
||||||
version = "2.5.0"
|
version = "2.5.0"
|
||||||
@@ -983,6 +1050,15 @@ dependencies = [
|
|||||||
"adler",
|
"adler",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "miniz_oxide"
|
||||||
|
version = "0.6.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "b275950c28b37e794e8c55d88aeb5e139d0ce23fdbbeda68f8d7174abdf9e8fa"
|
||||||
|
dependencies = [
|
||||||
|
"adler",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "mio"
|
name = "mio"
|
||||||
version = "0.7.14"
|
version = "0.7.14"
|
||||||
@@ -1053,6 +1129,16 @@ dependencies = [
|
|||||||
"winapi",
|
"winapi",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "nu-ansi-term"
|
||||||
|
version = "0.46.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "77a8165726e8236064dbb45459242600304b42a5ea24ee2948e18e023bf7ba84"
|
||||||
|
dependencies = [
|
||||||
|
"overload",
|
||||||
|
"winapi",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "num-integer"
|
name = "num-integer"
|
||||||
version = "0.1.45"
|
version = "0.1.45"
|
||||||
@@ -1074,23 +1160,14 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "num_cpus"
|
name = "num_cpus"
|
||||||
version = "1.13.1"
|
version = "1.14.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "19e64526ebdee182341572e50e9ad03965aa510cd94427a4549448f285e957a1"
|
checksum = "f6058e64324c71e02bc2b150e4f3bc8286db6c83092132ffa3f6b1eab0f9def5"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"hermit-abi",
|
"hermit-abi",
|
||||||
"libc",
|
"libc",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "num_threads"
|
|
||||||
version = "0.1.6"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "2819ce041d2ee131036f4fc9d6ae7ae125a3a40e97ba64d04fe799ad9dabbb44"
|
|
||||||
dependencies = [
|
|
||||||
"libc",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "number_prefix"
|
name = "number_prefix"
|
||||||
version = "0.4.0"
|
version = "0.4.0"
|
||||||
@@ -1126,6 +1203,15 @@ dependencies = [
|
|||||||
"objc",
|
"objc",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "object"
|
||||||
|
version = "0.29.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "21158b2c33aa6d4561f1c0a6ea283ca92bc54802a93b263e910746d679a7eb53"
|
||||||
|
dependencies = [
|
||||||
|
"memchr",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "once_cell"
|
name = "once_cell"
|
||||||
version = "1.16.0"
|
version = "1.16.0"
|
||||||
@@ -1154,9 +1240,21 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "os_str_bytes"
|
name = "os_str_bytes"
|
||||||
version = "6.3.1"
|
version = "6.4.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "3baf96e39c5359d2eb0dd6ccb42c62b91d9678aa68160d261b9e0ccbf9e9dea9"
|
checksum = "9b7820b9daea5457c9f21c69448905d723fbd21136ccf521748f23fd49e723ee"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "overload"
|
||||||
|
version = "0.1.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "b15813163c1d831bf4a13c3610c05c0d03b39feb07f7e09fa234dac9b15aaf39"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "owo-colors"
|
||||||
|
version = "3.5.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "c1b04fb49957986fdce4d6ee7a65027d55d4b6d2265e5848bbb507b58ccfdb6f"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "parking"
|
name = "parking"
|
||||||
@@ -1176,9 +1274,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "parking_lot_core"
|
name = "parking_lot_core"
|
||||||
version = "0.9.4"
|
version = "0.9.5"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "4dc9e0dc2adc1c69d09143aff38d3d30c5c3f0df0dad82e6d25547af174ebec0"
|
checksum = "7ff9f3fef3968a3ec5945535ed654cb38ff72d7495a25619e2247fb15a2ed9ba"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"cfg-if",
|
"cfg-if",
|
||||||
"libc",
|
"libc",
|
||||||
@@ -1220,33 +1318,23 @@ checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "polling"
|
name = "polling"
|
||||||
version = "2.4.0"
|
version = "2.5.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "ab4609a838d88b73d8238967b60dd115cc08d38e2bbaf51ee1e4b695f89122e2"
|
checksum = "166ca89eb77fd403230b9c156612965a81e094ec6ec3aa13663d4c8b113fa748"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"autocfg",
|
"autocfg",
|
||||||
"cfg-if",
|
"cfg-if",
|
||||||
"libc",
|
"libc",
|
||||||
"log",
|
"log",
|
||||||
"wepoll-ffi",
|
"wepoll-ffi",
|
||||||
"winapi",
|
"windows-sys",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "ppv-lite86"
|
name = "ppv-lite86"
|
||||||
version = "0.2.16"
|
version = "0.2.17"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "eb9f9e6e233e5c4a35559a617bf40a4ec447db2e84c20b55a6f83167b7e57872"
|
checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de"
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "pretty_env_logger"
|
|
||||||
version = "0.4.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "926d36b9553851b8b0005f1275891b392ee4d2d833852c417ed025477350fb9d"
|
|
||||||
dependencies = [
|
|
||||||
"env_logger",
|
|
||||||
"log",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "proc-macro-crate"
|
name = "proc-macro-crate"
|
||||||
@@ -1292,12 +1380,6 @@ dependencies = [
|
|||||||
"unicode-ident",
|
"unicode-ident",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "quick-error"
|
|
||||||
version = "1.2.3"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "a1d01941d82fa2ab50be1e79e6714289dd7cde78eba4c074bc5a4374f650dfe0"
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "quick-xml"
|
name = "quick-xml"
|
||||||
version = "0.22.0"
|
version = "0.22.0"
|
||||||
@@ -1387,10 +1469,19 @@ dependencies = [
|
|||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "regex-syntax"
|
name = "regex-automata"
|
||||||
version = "0.6.27"
|
version = "0.1.10"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "a3f87b73ce11b1619a3c6332f45341e0047173771e8b8b73f87bfeefb7b56244"
|
checksum = "6c230d73fb8d8c1b9c0b3135c5142a8acee3a0558fb8db5cf1cb65f8d7862132"
|
||||||
|
dependencies = [
|
||||||
|
"regex-syntax",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "regex-syntax"
|
||||||
|
version = "0.6.28"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "456c603be3e8d448b072f410900c09faf164fbce2d480456f50eea6e25f9c848"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "remove_dir_all"
|
name = "remove_dir_all"
|
||||||
@@ -1403,9 +1494,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "reqwest"
|
name = "reqwest"
|
||||||
version = "0.11.12"
|
version = "0.11.13"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "431949c384f4e2ae07605ccaa56d1d9d2ecdb5cadd4f9577ccfab29f2e5149fc"
|
checksum = "68cc60575865c7831548863cc02356512e3f1dc2f3f82cb837d7fc4cc8f3c97c"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"base64",
|
"base64",
|
||||||
"bytes",
|
"bytes",
|
||||||
@@ -1455,6 +1546,12 @@ dependencies = [
|
|||||||
"winapi",
|
"winapi",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "roff"
|
||||||
|
version = "0.2.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "b833d8d034ea094b1ea68aa6d5c740e0d04bad9d16568d08ba6f76823a114316"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "rust-ini"
|
name = "rust-ini"
|
||||||
version = "0.18.0"
|
version = "0.18.0"
|
||||||
@@ -1465,6 +1562,12 @@ dependencies = [
|
|||||||
"ordered-multimap",
|
"ordered-multimap",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "rustc-demangle"
|
||||||
|
version = "0.1.21"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "7ef03e0a2b150c7a90d01faf6254c9c48a41e95fb2a8c2ac1c6f0d2b9aefc342"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "rustls"
|
name = "rustls"
|
||||||
version = "0.20.7"
|
version = "0.20.7"
|
||||||
@@ -1558,18 +1661,18 @@ checksum = "e25dfac463d778e353db5be2449d1cce89bd6fd23c9f1ea21310ce6e5a1b29c4"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "serde"
|
name = "serde"
|
||||||
version = "1.0.147"
|
version = "1.0.148"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "d193d69bae983fc11a79df82342761dfbf28a99fc8d203dca4c3c1b590948965"
|
checksum = "e53f64bb4ba0191d6d0676e1b141ca55047d83b74f5607e6d8eb88126c52c2dc"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"serde_derive",
|
"serde_derive",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "serde_derive"
|
name = "serde_derive"
|
||||||
version = "1.0.147"
|
version = "1.0.148"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "4f1d362ca8fc9c3e3a7484440752472d68a6caa98f1ab81d99b5dfe517cec852"
|
checksum = "a55492425aa53521babf6137309e7d34c20bbfbbfcfe2c7f3a047fd1f6b92c0c"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
@@ -1578,9 +1681,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "serde_json"
|
name = "serde_json"
|
||||||
version = "1.0.87"
|
version = "1.0.89"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "6ce777b7b150d76b9cf60d28b55f5847135a003f7d7350c6be7a773508ce7d45"
|
checksum = "020ff22c755c2ed3f8cf162dbb41a7268d934702f3ed3631656ea597e08fc3db"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"itoa",
|
"itoa",
|
||||||
"ryu",
|
"ryu",
|
||||||
@@ -1625,6 +1728,15 @@ version = "1.0.0"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "ae1a47186c03a32177042e55dbc5fd5aee900b8e0069a8d70fba96a9375cd012"
|
checksum = "ae1a47186c03a32177042e55dbc5fd5aee900b8e0069a8d70fba96a9375cd012"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "sharded-slab"
|
||||||
|
version = "0.1.4"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "900fba806f70c630b0a382d0d825e17a0f19fcd059a2ade1ff237bcddf446b31"
|
||||||
|
dependencies = [
|
||||||
|
"lazy_static",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "shell-words"
|
name = "shell-words"
|
||||||
version = "1.1.0"
|
version = "1.1.0"
|
||||||
@@ -1737,25 +1849,15 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "syn"
|
name = "syn"
|
||||||
version = "1.0.103"
|
version = "1.0.104"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "a864042229133ada95abf3b54fdc62ef5ccabe9515b64717bcb9a1919e59445d"
|
checksum = "4ae548ec36cf198c0ef7710d3c230987c2d6d7bd98ad6edc0274462724c585ce"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"unicode-ident",
|
"unicode-ident",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "sys-info"
|
|
||||||
version = "0.9.1"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "0b3a0d0aba8bf96a0e1ddfdc352fc53b3df7f39318c71854910c3c4b024ae52c"
|
|
||||||
dependencies = [
|
|
||||||
"cc",
|
|
||||||
"libc",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "tar"
|
name = "tar"
|
||||||
version = "0.4.38"
|
version = "0.4.38"
|
||||||
@@ -1813,9 +1915,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "textwrap"
|
name = "textwrap"
|
||||||
version = "0.15.1"
|
version = "0.15.2"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "949517c0cf1bf4ee812e2e07e08ab448e3ae0d23472aee8a06c985f0c8815b16"
|
checksum = "b7b3e525a49ec206798b40326a44121291b530c963cfb01018f63e135bac543d"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "thiserror"
|
name = "thiserror"
|
||||||
@@ -1838,10 +1940,19 @@ dependencies = [
|
|||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "time"
|
name = "thread_local"
|
||||||
version = "0.1.44"
|
version = "1.1.4"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "6db9e6914ab8b1ae1c260a4ae7a49b6c5611b40328a735b21862567685e73255"
|
checksum = "5516c27b78311c50bf42c071425c560ac799b11c30b31f87e3081965fe5e0180"
|
||||||
|
dependencies = [
|
||||||
|
"once_cell",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "time"
|
||||||
|
version = "0.1.45"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "1b797afad3f312d1c66a56d11d0316f916356d11bd158fbc6ca6389ff6bf805a"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"libc",
|
"libc",
|
||||||
"wasi 0.10.0+wasi-snapshot-preview1",
|
"wasi 0.10.0+wasi-snapshot-preview1",
|
||||||
@@ -1850,13 +1961,11 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "time"
|
name = "time"
|
||||||
version = "0.3.16"
|
version = "0.3.17"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "0fab5c8b9980850e06d92ddbe3ab839c062c801f3927c0fb8abd6fc8e918fbca"
|
checksum = "a561bf4617eebd33bca6434b988f39ed798e527f51a1e797d0ee4f61c0a38376"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"itoa",
|
"itoa",
|
||||||
"libc",
|
|
||||||
"num_threads",
|
|
||||||
"serde",
|
"serde",
|
||||||
"time-core",
|
"time-core",
|
||||||
"time-macros",
|
"time-macros",
|
||||||
@@ -1870,9 +1979,9 @@ checksum = "2e153e1f1acaef8acc537e68b44906d2db6436e2b35ac2c6b42640fff91f00fd"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "time-macros"
|
name = "time-macros"
|
||||||
version = "0.2.5"
|
version = "0.2.6"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "65bb801831d812c562ae7d2bfb531f26e66e4e1f6b17307ba4149c5064710e5b"
|
checksum = "d967f99f534ca7e495c575c62638eebc2898a8c84c119b89e250477bc4ba16b2"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"time-core",
|
"time-core",
|
||||||
]
|
]
|
||||||
@@ -1946,23 +2055,24 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "topgrade"
|
name = "topgrade"
|
||||||
version = "10.1.0"
|
version = "10.2.1"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
|
||||||
"cfg-if",
|
"cfg-if",
|
||||||
"chrono",
|
"chrono",
|
||||||
"clap",
|
"clap",
|
||||||
|
"clap_complete",
|
||||||
|
"clap_mangen",
|
||||||
|
"color-eyre",
|
||||||
"console",
|
"console",
|
||||||
"directories",
|
"directories",
|
||||||
"futures",
|
"futures",
|
||||||
"glob",
|
"glob",
|
||||||
"home",
|
"home",
|
||||||
"lazy_static",
|
"lazy_static",
|
||||||
"log",
|
"libc",
|
||||||
"nix 0.24.2",
|
"nix 0.24.2",
|
||||||
"notify-rust",
|
"notify-rust",
|
||||||
"parselnk",
|
"parselnk",
|
||||||
"pretty_env_logger",
|
|
||||||
"regex",
|
"regex",
|
||||||
"rust-ini",
|
"rust-ini",
|
||||||
"self_update",
|
"self_update",
|
||||||
@@ -1971,11 +2081,12 @@ dependencies = [
|
|||||||
"shell-words",
|
"shell-words",
|
||||||
"shellexpand",
|
"shellexpand",
|
||||||
"strum 0.24.1",
|
"strum 0.24.1",
|
||||||
"sys-info",
|
|
||||||
"tempfile",
|
"tempfile",
|
||||||
"thiserror",
|
"thiserror",
|
||||||
"tokio",
|
"tokio",
|
||||||
"toml",
|
"toml",
|
||||||
|
"tracing",
|
||||||
|
"tracing-subscriber",
|
||||||
"walkdir",
|
"walkdir",
|
||||||
"which",
|
"which",
|
||||||
"winapi",
|
"winapi",
|
||||||
@@ -1994,6 +2105,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||||||
checksum = "8ce8c33a8d48bd45d624a6e523445fd21ec13d3653cd51f681abf67418f54eb8"
|
checksum = "8ce8c33a8d48bd45d624a6e523445fd21ec13d3653cd51f681abf67418f54eb8"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"cfg-if",
|
"cfg-if",
|
||||||
|
"log",
|
||||||
"pin-project-lite",
|
"pin-project-lite",
|
||||||
"tracing-attributes",
|
"tracing-attributes",
|
||||||
"tracing-core",
|
"tracing-core",
|
||||||
@@ -2017,6 +2129,47 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||||||
checksum = "24eb03ba0eab1fd845050058ce5e616558e8f8d8fca633e6b163fe25c797213a"
|
checksum = "24eb03ba0eab1fd845050058ce5e616558e8f8d8fca633e6b163fe25c797213a"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"once_cell",
|
"once_cell",
|
||||||
|
"valuable",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "tracing-error"
|
||||||
|
version = "0.2.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "d686ec1c0f384b1277f097b2f279a2ecc11afe8c133c1aabf036a27cb4cd206e"
|
||||||
|
dependencies = [
|
||||||
|
"tracing",
|
||||||
|
"tracing-subscriber",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "tracing-log"
|
||||||
|
version = "0.1.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "78ddad33d2d10b1ed7eb9d1f518a5674713876e97e5bb9b7345a7984fbb4f922"
|
||||||
|
dependencies = [
|
||||||
|
"lazy_static",
|
||||||
|
"log",
|
||||||
|
"tracing-core",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "tracing-subscriber"
|
||||||
|
version = "0.3.16"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "a6176eae26dd70d0c919749377897b54a9276bd7061339665dd68777926b5a70"
|
||||||
|
dependencies = [
|
||||||
|
"matchers",
|
||||||
|
"nu-ansi-term",
|
||||||
|
"once_cell",
|
||||||
|
"regex",
|
||||||
|
"sharded-slab",
|
||||||
|
"smallvec",
|
||||||
|
"thread_local",
|
||||||
|
"time 0.3.17",
|
||||||
|
"tracing",
|
||||||
|
"tracing-core",
|
||||||
|
"tracing-log",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -2085,6 +2238,12 @@ dependencies = [
|
|||||||
"percent-encoding",
|
"percent-encoding",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "valuable"
|
||||||
|
version = "0.1.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "830b7e5d4d90034032940e4ace0d9a9a057e7a45cd94e6c007832e39edb82f6d"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "version_check"
|
name = "version_check"
|
||||||
version = "0.9.4"
|
version = "0.9.4"
|
||||||
@@ -2454,9 +2613,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "zbus_names"
|
name = "zbus_names"
|
||||||
version = "2.2.0"
|
version = "2.3.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "41a408fd8a352695690f53906dc7fd036be924ec51ea5e05666ff42685ed0af5"
|
checksum = "d69bb79b44e1901ed8b217e485d0f01991aec574479b68cb03415f142bc7ae67"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"serde",
|
"serde",
|
||||||
"static_assertions",
|
"static_assertions",
|
||||||
@@ -2473,14 +2632,14 @@ dependencies = [
|
|||||||
"crc32fast",
|
"crc32fast",
|
||||||
"crossbeam-utils",
|
"crossbeam-utils",
|
||||||
"flate2",
|
"flate2",
|
||||||
"time 0.3.16",
|
"time 0.3.17",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "zvariant"
|
name = "zvariant"
|
||||||
version = "3.7.1"
|
version = "3.8.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "b794fb7f59af4105697b0449ba31731ee5dbb3e773a17dbdf3d36206ea1b1644"
|
checksum = "5c817f416f05fcbc833902f1e6064b72b1778573978cfeac54731451ccc9e207"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"byteorder",
|
"byteorder",
|
||||||
"enumflags2",
|
"enumflags2",
|
||||||
@@ -2492,9 +2651,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "zvariant_derive"
|
name = "zvariant_derive"
|
||||||
version = "3.7.1"
|
version = "3.8.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "dd58d4b6c8e26d3dd2149c8c40c6613ef6451b9885ff1296d1ac86c388351a54"
|
checksum = "fdd24fffd02794a76eb10109de463444064c88f5adb9e9d1a78488adc332bfef"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro-crate",
|
"proc-macro-crate",
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
|
|||||||
24
Cargo.toml
24
Cargo.toml
@@ -3,9 +3,10 @@ name = "topgrade"
|
|||||||
description = "Upgrade all the things"
|
description = "Upgrade all the things"
|
||||||
categories = ["os"]
|
categories = ["os"]
|
||||||
keywords = ["upgrade", "update"]
|
keywords = ["upgrade", "update"]
|
||||||
license-file = "LICENSE"
|
license = "GPL-3.0"
|
||||||
|
# license-file = "LICENSE"
|
||||||
repository = "https://github.com/topgrade-rs/topgrade"
|
repository = "https://github.com/topgrade-rs/topgrade"
|
||||||
version = "10.1.0"
|
version = "10.2.1"
|
||||||
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"]
|
exclude = ["doc/screenshot.gif"]
|
||||||
edition = "2021"
|
edition = "2021"
|
||||||
@@ -27,29 +28,40 @@ toml = "0.5"
|
|||||||
which_crate = { version = "~4.1", package = "which" }
|
which_crate = { version = "~4.1", package = "which" }
|
||||||
shellexpand = "~2.1"
|
shellexpand = "~2.1"
|
||||||
clap = { version = "~3.1", features = ["cargo", "derive"] }
|
clap = { version = "~3.1", features = ["cargo", "derive"] }
|
||||||
log = "~0.4"
|
clap_complete = "~3.1"
|
||||||
|
clap_mangen = "~0.1"
|
||||||
walkdir = "~2.3"
|
walkdir = "~2.3"
|
||||||
console = "~0.15"
|
console = "~0.15"
|
||||||
lazy_static = "~1.4"
|
lazy_static = "~1.4"
|
||||||
chrono = "~0.4"
|
chrono = "~0.4"
|
||||||
pretty_env_logger = "~0.4"
|
|
||||||
glob = "~0.3"
|
glob = "~0.3"
|
||||||
strum = { version = "~0.24", features = ["derive"] }
|
strum = { version = "~0.24", features = ["derive"] }
|
||||||
thiserror = "~1.0"
|
thiserror = "~1.0"
|
||||||
anyhow = "~1.0"
|
|
||||||
tempfile = "~3.2"
|
tempfile = "~3.2"
|
||||||
cfg-if = "~1.0"
|
cfg-if = "~1.0"
|
||||||
tokio = { version = "~1.5", features = ["process", "rt-multi-thread"] }
|
tokio = { version = "~1.5", features = ["process", "rt-multi-thread"] }
|
||||||
futures = "~0.3"
|
futures = "~0.3"
|
||||||
regex = "~1.5"
|
regex = "~1.5"
|
||||||
sys-info = "~0.9"
|
|
||||||
semver = "~1.0"
|
semver = "~1.0"
|
||||||
shell-words = "~1.1"
|
shell-words = "~1.1"
|
||||||
|
color-eyre = "0.6.2"
|
||||||
|
tracing = { version = "0.1.37", features = ["attributes", "log"] }
|
||||||
|
tracing-subscriber = { version = "0.3.16", features = ["env-filter", "time"] }
|
||||||
|
|
||||||
[target.'cfg(target_os = "macos")'.dependencies]
|
[target.'cfg(target_os = "macos")'.dependencies]
|
||||||
notify-rust = "~4.5"
|
notify-rust = "~4.5"
|
||||||
|
|
||||||
|
[package.metadata.generate-rpm]
|
||||||
|
assets = [{source = "target/release/topgrade", dest="/usr/bin/topgrade"}]
|
||||||
|
|
||||||
|
[package.metadata.generate-rpm.requires]
|
||||||
|
git = "*"
|
||||||
|
|
||||||
|
[package.metadata.deb]
|
||||||
|
depends = "$auto,git"
|
||||||
|
|
||||||
[target.'cfg(unix)'.dependencies]
|
[target.'cfg(unix)'.dependencies]
|
||||||
|
libc = "~0.2"
|
||||||
nix = "~0.24"
|
nix = "~0.24"
|
||||||
rust-ini = "~0.18"
|
rust-ini = "~0.18"
|
||||||
self_update_crate = { version = "~0.30", default-features = false, optional = true, package = "self_update", features = ["archive-tar", "compression-flate2", "rustls"] }
|
self_update_crate = { version = "~0.30", default-features = false, optional = true, package = "self_update", features = ["archive-tar", "compression-flate2", "rustls"] }
|
||||||
|
|||||||
4
Cross.toml
Normal file
4
Cross.toml
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
# Workaround for: https://github.com/cross-rs/cross/issues/1100
|
||||||
|
# TODO: Remove this file altogether once a new version of cross (after v0.2.4) is released.
|
||||||
|
[target.x86_64-unknown-freebsd.env]
|
||||||
|
passthrough = ["AR_x86_64_unknown_freebsd=x86_64-unknown-freebsd12-ar"]
|
||||||
60
README.md
60
README.md
@@ -1,12 +1,12 @@
|
|||||||
<div align="center">
|
<div align="center">
|
||||||
<img alt="Topgrade" src="doc/topgrade.png" width="850px">
|
<h1>
|
||||||
|
<img alt="Topgrade" src="doc/topgrade_transparent.png" width="850px">
|
||||||
|
</h1>
|
||||||
|
|
||||||
<!--
|
<a href="https://github.com/topgrade-rs/topgrade/releases"><img alt="GitHub Release" src="https://img.shields.io/github/release/topgrade-rs/topgrade.svg"></a>
|
||||||
<a href="https://github.com/topgrade-rs/topgrade/releases"><img alt="GitHub Release" src="https://img.shields.io/github/release/r-darwish/topgrade.svg"></a>
|
|
||||||
<a href="https://crates.io/crates/topgrade"><img alt="crates.io" src="https://img.shields.io/crates/v/topgrade.svg"></a>
|
<a href="https://crates.io/crates/topgrade"><img alt="crates.io" src="https://img.shields.io/crates/v/topgrade.svg"></a>
|
||||||
<a href="https://aur.archlinux.org/packages/topgrade"><img alt="AUR" src="https://img.shields.io/aur/version/topgrade.svg"></a>
|
<a href="https://aur.archlinux.org/packages/topgrade"><img alt="AUR" src="https://img.shields.io/aur/version/topgrade.svg"></a>
|
||||||
<a href="https://formulae.brew.sh/formula/topgrade"><img alt="Homebrew" src="https://img.shields.io/homebrew/v/topgrade.svg"></a>
|
<a href="https://formulae.brew.sh/formula/topgrade"><img alt="Homebrew" src="https://img.shields.io/homebrew/v/topgrade.svg"></a>
|
||||||
-->
|
|
||||||
|
|
||||||
<img alt="Demo" src="doc/screenshot.gif" width="550px">
|
<img alt="Demo" src="doc/screenshot.gif" width="550px">
|
||||||
</div>
|
</div>
|
||||||
@@ -22,48 +22,55 @@ To remedy this, **Topgrade** detects which tools you use and runs the appropriat
|
|||||||
|
|
||||||
## Installation
|
## Installation
|
||||||
|
|
||||||
- Arch Linux: [AUR](https://aur.archlinux.org/packages/topgrade) package.
|
[](https://repology.org/project/topgrade/versions)
|
||||||
- NixOS: _topgrade_ package in `nixpkgs`.
|
|
||||||
- macOS: [Homebrew](https://formulae.brew.sh/formula/topgrade) or [MacPorts](https://ports.macports.org/port/topgrade/).
|
|
||||||
|
|
||||||
Other systems users can either use `cargo install` or use the compiled binaries from the release page.
|
- Arch Linux: [AUR](https://aur.archlinux.org/packages/topgrade)
|
||||||
|
- NixOS: [Nixpkgs](https://search.nixos.org/packages?show=topgrade)
|
||||||
|
- Void Linux: [XBPS](https://voidlinux.org/packages/?arch=x86_64&q=topgrade)
|
||||||
|
- macOS: [Homebrew](https://formulae.brew.sh/formula/topgrade) or [MacPorts](https://ports.macports.org/port/topgrade/)
|
||||||
|
|
||||||
|
Other systems users can either use `cargo install` or the compiled binaries from the release page.
|
||||||
The compiled binaries contain a self-upgrading feature.
|
The compiled binaries contain a self-upgrading feature.
|
||||||
|
|
||||||
Topgrade requires Rust 1.51 or above.
|
Topgrade requires Rust 1.60 or above.
|
||||||
|
|
||||||
## Documentation
|
|
||||||
|
|
||||||
> **Warning**
|
|
||||||
> Work in Progress
|
|
||||||
|
|
||||||
You can visit the documentation at [topgrade-rs.github.io](https://topgrade-rs.github.io/) .
|
|
||||||
|
|
||||||
## Usage
|
## Usage
|
||||||
|
|
||||||
Just run `topgrade`.
|
Just run `topgrade`.
|
||||||
See [the documentation](https://topgrade-rs.github.io/) for the list of things Topgrade supports.
|
|
||||||
|
Visit the documentation at [topgrade-rs.github.io](https://topgrade-rs.github.io/) for more information.
|
||||||
|
|
||||||
|
> **Warning**
|
||||||
|
> Work in Progress
|
||||||
|
|
||||||
## Customization
|
## Customization
|
||||||
|
|
||||||
See `config.example.toml` for an example configuration file.
|
See `config.example.toml` for an example configuration file.
|
||||||
|
|
||||||
### Configuration path
|
### Configuration Path
|
||||||
|
|
||||||
The configuration should be placed in the following paths depending by the operating system:
|
The configuration should be placed in the following paths depending on the operating system:
|
||||||
|
|
||||||
- **Windows** - `%APPDATA%/topgrade.toml`
|
- **Windows** - `%APPDATA%/topgrade.toml`
|
||||||
- **macOS** and **other Unix systems** - `${XDG_CONFIG_HOME:-~/.config}/topgrade.toml`
|
- **macOS** and **other Unix systems** - `${XDG_CONFIG_HOME:-~/.config}/topgrade.toml`
|
||||||
|
|
||||||
|
## Remote Execution
|
||||||
|
|
||||||
|
You can specify a key called `remote_topgrades` in the configuration file.
|
||||||
|
This key should contain a list of hostnames that have Topgrade installed on them.
|
||||||
|
Topgrade will use `ssh` to run `topgrade` on remote hosts before acting locally.
|
||||||
|
To limit the execution only to specific hosts use the `--remote-host-limit` parameter.
|
||||||
|
|
||||||
## Contribution
|
## Contribution
|
||||||
|
|
||||||
### Problems or missing features?
|
### Problems or missing features?
|
||||||
|
|
||||||
Open a new Issue describing your problem and if possible with a possible solution.
|
Open a new issue describing your problem and if possible provide a solution.
|
||||||
|
|
||||||
### Missing a feature or found an unsupported tool/distro?
|
### Missing a feature or found an unsupported tool/distro?
|
||||||
|
|
||||||
Just let us now what you are missing by opening an issue.
|
Just let us now what you are missing by opening an issue.
|
||||||
For tools please open an Issue describing the tool, which platforms it supports and if possible, give us an example of its usage.
|
For tools, please open an issue describing the tool, which platforms it supports and if possible, give us an example of its usage.
|
||||||
|
|
||||||
### Want to contribute to the code?
|
### Want to contribute to the code?
|
||||||
|
|
||||||
@@ -73,16 +80,9 @@ Just fork the repository and start coding.
|
|||||||
|
|
||||||
- Check if your code passes `cargo fmt` and `cargo clippy`.
|
- Check if your code passes `cargo fmt` and `cargo clippy`.
|
||||||
- Check if your code is self explanatory, if not it should be documented by comments.
|
- Check if your code is self explanatory, if not it should be documented by comments.
|
||||||
- Make a Pull Request to the dev branch for new features or to the bug-fixes branch for bug fixes.
|
- Make a pull request to the `dev` branch for new features or to the `bug-fixes` branch for bug fixes.
|
||||||
|
|
||||||
## Remote execution
|
## Roadmap
|
||||||
|
|
||||||
You can specify a key called `remote_topgrades` in the configuration file.
|
|
||||||
This key should contain a list of hostnames that have Topgrade installed on them.
|
|
||||||
Topgrade will use `ssh` to run `topgrade` on remote hosts before acting locally.
|
|
||||||
To limit the execution only to specific hosts use the `--remote-host-limit` parameter.
|
|
||||||
|
|
||||||
## ToDo
|
|
||||||
|
|
||||||
- [ ] Add a proper testing framework to the code base.
|
- [ ] Add a proper testing framework to the code base.
|
||||||
- [ ] Add unit tests for package managers.
|
- [ ] Add unit tests for package managers.
|
||||||
|
|||||||
11
SECURITY.md
Normal file
11
SECURITY.md
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
# Security Policy
|
||||||
|
|
||||||
|
## Supported Versions
|
||||||
|
|
||||||
|
We only support the latest major version and each subversion.
|
||||||
|
|
||||||
|
| Version | Supported |
|
||||||
|
| -------- | ------------------ |
|
||||||
|
| 10.0.x | :white_check_mark: |
|
||||||
|
| < 10.0 | :x: |
|
||||||
|
|
||||||
5
clippy.toml
Normal file
5
clippy.toml
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
disallowed-methods = [
|
||||||
|
{ path = "std::process::Command::output", reason = "Use `output_checked[_with][_utf8]`" },
|
||||||
|
{ path = "std::process::Command::spawn", reason = "Use `spawn_checked`" },
|
||||||
|
{ path = "std::process::Command::status", reason = "Use `status_checked`" },
|
||||||
|
]
|
||||||
@@ -13,6 +13,10 @@
|
|||||||
# Do not ask to retry failed steps (default: false)
|
# Do not ask to retry failed steps (default: false)
|
||||||
#no_retry = true
|
#no_retry = true
|
||||||
|
|
||||||
|
# Run `sudo -v` to cache credentials at the start of the run; this avoids a
|
||||||
|
# blocking password prompt in the middle of a possibly-unattended run.
|
||||||
|
#pre_sudo = false
|
||||||
|
|
||||||
# Run inside tmux
|
# Run inside tmux
|
||||||
#run_in_tmux = true
|
#run_in_tmux = true
|
||||||
|
|
||||||
|
|||||||
BIN
doc/topgrade_transparent.png
Normal file
BIN
doc/topgrade_transparent.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 34 KiB |
244
src/command.rs
Normal file
244
src/command.rs
Normal file
@@ -0,0 +1,244 @@
|
|||||||
|
//! Utilities for running commands and providing user-friendly error messages.
|
||||||
|
|
||||||
|
use std::fmt::Display;
|
||||||
|
use std::process::Child;
|
||||||
|
use std::process::{Command, ExitStatus, Output};
|
||||||
|
|
||||||
|
use color_eyre::eyre;
|
||||||
|
use color_eyre::eyre::eyre;
|
||||||
|
use color_eyre::eyre::Context;
|
||||||
|
|
||||||
|
use crate::error::TopgradeError;
|
||||||
|
|
||||||
|
/// Like [`Output`], but UTF-8 decoded.
|
||||||
|
#[derive(Clone, Debug, PartialEq, Eq)]
|
||||||
|
pub struct Utf8Output {
|
||||||
|
pub status: ExitStatus,
|
||||||
|
pub stdout: String,
|
||||||
|
pub stderr: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl TryFrom<Output> for Utf8Output {
|
||||||
|
type Error = eyre::Error;
|
||||||
|
|
||||||
|
fn try_from(Output { status, stdout, stderr }: Output) -> Result<Self, Self::Error> {
|
||||||
|
let stdout = String::from_utf8(stdout).map_err(|err| {
|
||||||
|
eyre!(
|
||||||
|
"Stdout contained invalid UTF-8: {}",
|
||||||
|
String::from_utf8_lossy(err.as_bytes())
|
||||||
|
)
|
||||||
|
})?;
|
||||||
|
let stderr = String::from_utf8(stderr).map_err(|err| {
|
||||||
|
eyre!(
|
||||||
|
"Stderr contained invalid UTF-8: {}",
|
||||||
|
String::from_utf8_lossy(err.as_bytes())
|
||||||
|
)
|
||||||
|
})?;
|
||||||
|
|
||||||
|
Ok(Utf8Output { status, stdout, stderr })
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl TryFrom<&Output> for Utf8Output {
|
||||||
|
type Error = eyre::Error;
|
||||||
|
|
||||||
|
fn try_from(Output { status, stdout, stderr }: &Output) -> Result<Self, Self::Error> {
|
||||||
|
let stdout = String::from_utf8(stdout.to_vec()).map_err(|err| {
|
||||||
|
eyre!(
|
||||||
|
"Stdout contained invalid UTF-8: {}",
|
||||||
|
String::from_utf8_lossy(err.as_bytes())
|
||||||
|
)
|
||||||
|
})?;
|
||||||
|
let stderr = String::from_utf8(stderr.to_vec()).map_err(|err| {
|
||||||
|
eyre!(
|
||||||
|
"Stderr contained invalid UTF-8: {}",
|
||||||
|
String::from_utf8_lossy(err.as_bytes())
|
||||||
|
)
|
||||||
|
})?;
|
||||||
|
let status = *status;
|
||||||
|
|
||||||
|
Ok(Utf8Output { status, stdout, stderr })
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Display for Utf8Output {
|
||||||
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
|
write!(f, "{}", self.stdout)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Extension trait for [`Command`], adding helpers to gather output while checking the exit
|
||||||
|
/// status.
|
||||||
|
///
|
||||||
|
/// These also give us significantly better error messages, which include:
|
||||||
|
///
|
||||||
|
/// 1. The command and arguments that were executed, escaped with familiar `sh` syntax.
|
||||||
|
/// 2. The exit status of the command or the signal that killed it.
|
||||||
|
/// 3. If we were capturing the output of the command, rather than forwarding it to the user's
|
||||||
|
/// stdout/stderr, the error message includes the command's stdout and stderr output.
|
||||||
|
///
|
||||||
|
/// Additionally, executing commands with these methods will log the command at debug-level,
|
||||||
|
/// useful when gathering error reports.
|
||||||
|
pub trait CommandExt {
|
||||||
|
type Child;
|
||||||
|
|
||||||
|
/// Like [`Command::output`], but checks the exit status and provides nice error messages.
|
||||||
|
///
|
||||||
|
/// Returns an `Err` if the command failed to execute or returned a non-zero exit code.
|
||||||
|
#[track_caller]
|
||||||
|
fn output_checked(&mut self) -> eyre::Result<Output> {
|
||||||
|
self.output_checked_with(|output: &Output| if output.status.success() { Ok(()) } else { Err(()) })
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Like [`output_checked`], but also decodes Stdout and Stderr as UTF-8.
|
||||||
|
///
|
||||||
|
/// Returns an `Err` if the command failed to execute, returned a non-zero exit code, or if the
|
||||||
|
/// output contains invalid UTF-8.
|
||||||
|
#[track_caller]
|
||||||
|
fn output_checked_utf8(&mut self) -> eyre::Result<Utf8Output> {
|
||||||
|
let output = self.output_checked()?;
|
||||||
|
output.try_into()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Like [`output_checked`] but a closure determines if the command failed instead of
|
||||||
|
/// [`ExitStatus::success`].
|
||||||
|
///
|
||||||
|
/// Returns an `Err` if the command failed to execute or if `succeeded` returns an `Err`.
|
||||||
|
/// (This lets the caller substitute their own notion of "success" instead of assuming
|
||||||
|
/// non-zero exit codes indicate success.)
|
||||||
|
#[track_caller]
|
||||||
|
fn output_checked_with(&mut self, succeeded: impl Fn(&Output) -> Result<(), ()>) -> eyre::Result<Output>;
|
||||||
|
|
||||||
|
/// Like [`output_checked_with`], but also decodes Stdout and Stderr as UTF-8.
|
||||||
|
///
|
||||||
|
/// Returns an `Err` if the command failed to execute, if `succeeded` returns an `Err`, or if
|
||||||
|
/// the output contains invalid UTF-8.
|
||||||
|
#[track_caller]
|
||||||
|
fn output_checked_with_utf8(
|
||||||
|
&mut self,
|
||||||
|
succeeded: impl Fn(&Utf8Output) -> Result<(), ()>,
|
||||||
|
) -> eyre::Result<Utf8Output> {
|
||||||
|
// This decodes the Stdout and Stderr as UTF-8 twice...
|
||||||
|
let output =
|
||||||
|
self.output_checked_with(|output| output.try_into().map_err(|_| ()).and_then(|o| succeeded(&o)))?;
|
||||||
|
output.try_into()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Like [`Command::status`], but gives a nice error message if the status is unsuccessful
|
||||||
|
/// rather than returning the [`ExitStatus`].
|
||||||
|
///
|
||||||
|
/// Returns `Ok` if the command executes successfully, returns `Err` if the command fails to
|
||||||
|
/// execute or returns a non-zero exit code.
|
||||||
|
#[track_caller]
|
||||||
|
fn status_checked(&mut self) -> eyre::Result<()> {
|
||||||
|
self.status_checked_with(|status| if status.success() { Ok(()) } else { Err(()) })
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Like [`status_checked`], but gives a nice error message if the status is unsuccessful
|
||||||
|
/// rather than returning the [`ExitStatus`].
|
||||||
|
///
|
||||||
|
/// Returns `Ok` if the command executes successfully, returns `Err` if the command fails to
|
||||||
|
/// execute or if `succeeded` returns an `Err`.
|
||||||
|
/// (This lets the caller substitute their own notion of "success" instead of assuming
|
||||||
|
/// non-zero exit codes indicate success.)
|
||||||
|
#[track_caller]
|
||||||
|
fn status_checked_with(&mut self, succeeded: impl Fn(ExitStatus) -> Result<(), ()>) -> eyre::Result<()>;
|
||||||
|
|
||||||
|
/// Like [`Command::spawn`], but gives a nice error message if the command fails to
|
||||||
|
/// execute.
|
||||||
|
#[track_caller]
|
||||||
|
fn spawn_checked(&mut self) -> eyre::Result<Self::Child>;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl CommandExt for Command {
|
||||||
|
type Child = Child;
|
||||||
|
|
||||||
|
fn output_checked_with(&mut self, succeeded: impl Fn(&Output) -> Result<(), ()>) -> eyre::Result<Output> {
|
||||||
|
let command = log(self);
|
||||||
|
|
||||||
|
// This is where we implement `output_checked`, which is what we prefer to use instead of
|
||||||
|
// `output`, so we allow `Command::output` here.
|
||||||
|
#[allow(clippy::disallowed_methods)]
|
||||||
|
let output = self
|
||||||
|
.output()
|
||||||
|
.with_context(|| format!("Failed to execute `{command}`"))?;
|
||||||
|
|
||||||
|
if succeeded(&output).is_ok() {
|
||||||
|
Ok(output)
|
||||||
|
} else {
|
||||||
|
let mut message = format!("Command failed: `{command}`");
|
||||||
|
let stderr = String::from_utf8_lossy(&output.stderr);
|
||||||
|
let stdout = String::from_utf8_lossy(&output.stdout);
|
||||||
|
|
||||||
|
let stdout_trimmed = stdout.trim();
|
||||||
|
if !stdout_trimmed.is_empty() {
|
||||||
|
message.push_str(&format!("\n\nStdout:\n{stdout_trimmed}"));
|
||||||
|
}
|
||||||
|
let stderr_trimmed = stderr.trim();
|
||||||
|
if !stderr_trimmed.is_empty() {
|
||||||
|
message.push_str(&format!("\n\nStderr:\n{stderr_trimmed}"));
|
||||||
|
}
|
||||||
|
|
||||||
|
let (program, _) = get_program_and_args(self);
|
||||||
|
let err = TopgradeError::ProcessFailedWithOutput(program, output.status, stderr.into_owned());
|
||||||
|
|
||||||
|
let ret = Err(err).with_context(|| message);
|
||||||
|
tracing::debug!("Command failed: {ret:?}");
|
||||||
|
ret
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn status_checked_with(&mut self, succeeded: impl Fn(ExitStatus) -> Result<(), ()>) -> eyre::Result<()> {
|
||||||
|
let command = log(self);
|
||||||
|
let message = format!("Failed to execute `{command}`");
|
||||||
|
|
||||||
|
// This is where we implement `status_checked`, which is what we prefer to use instead of
|
||||||
|
// `status`, so we allow `Command::status` here.
|
||||||
|
#[allow(clippy::disallowed_methods)]
|
||||||
|
let status = self.status().with_context(|| message.clone())?;
|
||||||
|
|
||||||
|
if succeeded(status).is_ok() {
|
||||||
|
Ok(())
|
||||||
|
} else {
|
||||||
|
let (program, _) = get_program_and_args(self);
|
||||||
|
let err = TopgradeError::ProcessFailed(program, status);
|
||||||
|
let ret = Err(err).with_context(|| format!("Command failed: `{command}`"));
|
||||||
|
tracing::debug!("Command failed: {ret:?}");
|
||||||
|
ret
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn spawn_checked(&mut self) -> eyre::Result<Self::Child> {
|
||||||
|
let command = log(self);
|
||||||
|
let message = format!("Failed to execute `{command}`");
|
||||||
|
|
||||||
|
// This is where we implement `spawn_checked`, which is what we prefer to use instead of
|
||||||
|
// `spawn`, so we allow `Command::spawn` here.
|
||||||
|
#[allow(clippy::disallowed_methods)]
|
||||||
|
{
|
||||||
|
self.spawn().with_context(|| message.clone())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_program_and_args(cmd: &Command) -> (String, String) {
|
||||||
|
// We're not doing anything weird with commands that are invalid UTF-8 so this is fine.
|
||||||
|
let program = cmd.get_program().to_string_lossy().into_owned();
|
||||||
|
let args = shell_words::join(cmd.get_args().map(|arg| arg.to_string_lossy()));
|
||||||
|
(program, args)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn format_program_and_args(cmd: &Command) -> String {
|
||||||
|
let (program, args) = get_program_and_args(cmd);
|
||||||
|
if args.is_empty() {
|
||||||
|
program
|
||||||
|
} else {
|
||||||
|
format!("{program} {args}")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn log(cmd: &Command) -> String {
|
||||||
|
let command = format_program_and_args(cmd);
|
||||||
|
tracing::debug!("Executing command `{command}`");
|
||||||
|
command
|
||||||
|
}
|
||||||
@@ -1,21 +1,25 @@
|
|||||||
#![allow(dead_code)]
|
#![allow(dead_code)]
|
||||||
use anyhow::Context;
|
|
||||||
use anyhow::Result;
|
|
||||||
use clap::{ArgEnum, Parser};
|
|
||||||
use directories::BaseDirs;
|
|
||||||
use log::debug;
|
|
||||||
use regex::Regex;
|
|
||||||
use serde::Deserialize;
|
|
||||||
use std::collections::BTreeMap;
|
use std::collections::BTreeMap;
|
||||||
use std::fs::write;
|
use std::fs::write;
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
use std::process::Command;
|
use std::process::Command;
|
||||||
use std::{env, fs};
|
use std::{env, fs};
|
||||||
|
|
||||||
|
use clap::{ArgEnum, Parser};
|
||||||
|
use clap_complete::Shell;
|
||||||
|
use color_eyre::eyre;
|
||||||
|
use color_eyre::eyre::Context;
|
||||||
|
use color_eyre::eyre::Result;
|
||||||
|
use directories::BaseDirs;
|
||||||
|
use regex::Regex;
|
||||||
|
use serde::Deserialize;
|
||||||
use strum::{EnumIter, EnumString, EnumVariantNames, IntoEnumIterator};
|
use strum::{EnumIter, EnumString, EnumVariantNames, IntoEnumIterator};
|
||||||
use sys_info::hostname;
|
use tracing::debug;
|
||||||
use which_crate::which;
|
use which_crate::which;
|
||||||
|
|
||||||
use super::utils::editor;
|
use crate::command::CommandExt;
|
||||||
|
|
||||||
|
use super::utils::{editor, hostname};
|
||||||
|
|
||||||
pub static EXAMPLE_CONFIG: &str = include_str!("../config.example.toml");
|
pub static EXAMPLE_CONFIG: &str = include_str!("../config.example.toml");
|
||||||
|
|
||||||
@@ -103,6 +107,7 @@ pub enum Step {
|
|||||||
HomeManager,
|
HomeManager,
|
||||||
Jetpack,
|
Jetpack,
|
||||||
Julia,
|
Julia,
|
||||||
|
Juliaup,
|
||||||
Kakoune,
|
Kakoune,
|
||||||
Krew,
|
Krew,
|
||||||
Macports,
|
Macports,
|
||||||
@@ -126,6 +131,7 @@ pub enum Step {
|
|||||||
Remotes,
|
Remotes,
|
||||||
Restarts,
|
Restarts,
|
||||||
Rtcl,
|
Rtcl,
|
||||||
|
RubyGems,
|
||||||
Rustup,
|
Rustup,
|
||||||
Scoop,
|
Scoop,
|
||||||
Sdkman,
|
Sdkman,
|
||||||
@@ -220,6 +226,7 @@ pub struct Brew {
|
|||||||
#[derive(Debug, Deserialize, Clone, Copy)]
|
#[derive(Debug, Deserialize, Clone, Copy)]
|
||||||
#[serde(rename_all = "snake_case")]
|
#[serde(rename_all = "snake_case")]
|
||||||
pub enum ArchPackageManager {
|
pub enum ArchPackageManager {
|
||||||
|
GarudaUpdate,
|
||||||
Autodetect,
|
Autodetect,
|
||||||
Trizen,
|
Trizen,
|
||||||
Paru,
|
Paru,
|
||||||
@@ -266,6 +273,7 @@ pub struct Vim {
|
|||||||
#[serde(deny_unknown_fields)]
|
#[serde(deny_unknown_fields)]
|
||||||
/// Configuration file
|
/// Configuration file
|
||||||
pub struct ConfigFile {
|
pub struct ConfigFile {
|
||||||
|
pre_sudo: Option<bool>,
|
||||||
pre_commands: Option<Commands>,
|
pre_commands: Option<Commands>,
|
||||||
post_commands: Option<Commands>,
|
post_commands: Option<Commands>,
|
||||||
commands: Option<Commands>,
|
commands: Option<Commands>,
|
||||||
@@ -348,12 +356,12 @@ impl ConfigFile {
|
|||||||
};
|
};
|
||||||
|
|
||||||
let contents = fs::read_to_string(&config_path).map_err(|e| {
|
let contents = fs::read_to_string(&config_path).map_err(|e| {
|
||||||
log::error!("Unable to read {}", config_path.display());
|
tracing::error!("Unable to read {}", config_path.display());
|
||||||
e
|
e
|
||||||
})?;
|
})?;
|
||||||
|
|
||||||
let mut result: Self = toml::from_str(&contents).map_err(|e| {
|
let mut result: Self = toml::from_str(&contents).map_err(|e| {
|
||||||
log::error!("Failed to deserialize {}", config_path.display());
|
tracing::error!("Failed to deserialize {}", config_path.display());
|
||||||
e
|
e
|
||||||
})?;
|
})?;
|
||||||
|
|
||||||
@@ -389,9 +397,8 @@ impl ConfigFile {
|
|||||||
Command::new(command)
|
Command::new(command)
|
||||||
.args(args)
|
.args(args)
|
||||||
.arg(config_path)
|
.arg(config_path)
|
||||||
.spawn()
|
.status_checked()
|
||||||
.and_then(|mut p| p.wait())?;
|
.context("Failed to open configuration file editor")
|
||||||
Ok(())
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -424,22 +431,22 @@ pub struct CommandLineArgs {
|
|||||||
no_retry: bool,
|
no_retry: bool,
|
||||||
|
|
||||||
/// Do not perform upgrades for the given steps
|
/// Do not perform upgrades for the given steps
|
||||||
#[clap(long = "disable", arg_enum, multiple_values = true)]
|
#[clap(long = "disable", value_name = "STEP", arg_enum, multiple_values = true)]
|
||||||
disable: Vec<Step>,
|
disable: Vec<Step>,
|
||||||
|
|
||||||
/// Perform only the specified steps (experimental)
|
/// Perform only the specified steps (experimental)
|
||||||
#[clap(long = "only", arg_enum, multiple_values = true)]
|
#[clap(long = "only", value_name = "STEP", arg_enum, multiple_values = true)]
|
||||||
only: Vec<Step>,
|
only: Vec<Step>,
|
||||||
|
|
||||||
/// Run only specific custom commands
|
/// Run only specific custom commands
|
||||||
#[clap(long = "custom-commands")]
|
#[clap(long = "custom-commands", value_name = "NAME", multiple_values = true)]
|
||||||
custom_commands: Vec<String>,
|
custom_commands: Vec<String>,
|
||||||
|
|
||||||
/// Set environment variables
|
/// Set environment variables
|
||||||
#[clap(long = "env", multiple_values = true)]
|
#[clap(long = "env", value_name = "NAME=VALUE", multiple_values = true)]
|
||||||
env: Vec<String>,
|
env: Vec<String>,
|
||||||
|
|
||||||
/// Output logs
|
/// Output debug logs. Alias for `--log-filter debug`.
|
||||||
#[clap(short = 'v', long = "verbose")]
|
#[clap(short = 'v', long = "verbose")]
|
||||||
pub verbose: bool,
|
pub verbose: bool,
|
||||||
|
|
||||||
@@ -452,7 +459,14 @@ pub struct CommandLineArgs {
|
|||||||
skip_notify: bool,
|
skip_notify: bool,
|
||||||
|
|
||||||
/// Say yes to package manager's prompt
|
/// Say yes to package manager's prompt
|
||||||
#[clap(short = 'y', long = "yes", arg_enum, multiple_values = true, min_values = 0)]
|
#[clap(
|
||||||
|
short = 'y',
|
||||||
|
long = "yes",
|
||||||
|
value_name = "STEP",
|
||||||
|
arg_enum,
|
||||||
|
multiple_values = true,
|
||||||
|
min_values = 0
|
||||||
|
)]
|
||||||
yes: Option<Vec<Step>>,
|
yes: Option<Vec<Step>>,
|
||||||
|
|
||||||
/// Don't pull the predefined git repos
|
/// Don't pull the predefined git repos
|
||||||
@@ -460,16 +474,30 @@ pub struct CommandLineArgs {
|
|||||||
disable_predefined_git_repos: bool,
|
disable_predefined_git_repos: bool,
|
||||||
|
|
||||||
/// Alternative configuration file
|
/// Alternative configuration file
|
||||||
#[clap(long = "config")]
|
#[clap(long = "config", value_name = "PATH")]
|
||||||
config: Option<PathBuf>,
|
config: Option<PathBuf>,
|
||||||
|
|
||||||
/// A regular expression for restricting remote host execution
|
/// A regular expression for restricting remote host execution
|
||||||
#[clap(long = "remote-host-limit")]
|
#[clap(long = "remote-host-limit", value_name = "REGEX")]
|
||||||
remote_host_limit: Option<Regex>,
|
remote_host_limit: Option<Regex>,
|
||||||
|
|
||||||
/// Show the reason for skipped steps
|
/// Show the reason for skipped steps
|
||||||
#[clap(long = "show-skipped")]
|
#[clap(long = "show-skipped")]
|
||||||
show_skipped: bool,
|
show_skipped: bool,
|
||||||
|
|
||||||
|
/// Tracing filter directives.
|
||||||
|
///
|
||||||
|
/// See: https://docs.rs/tracing-subscriber/latest/tracing_subscriber/struct.EnvFilter.html
|
||||||
|
#[clap(long, default_value = "info")]
|
||||||
|
pub log_filter: String,
|
||||||
|
|
||||||
|
/// Print completion script for the given shell and exit
|
||||||
|
#[clap(long, arg_enum, hide = true)]
|
||||||
|
pub gen_completion: Option<Shell>,
|
||||||
|
|
||||||
|
/// Print roff manpage and exit
|
||||||
|
#[clap(long, hide = true)]
|
||||||
|
pub gen_manpage: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl CommandLineArgs {
|
impl CommandLineArgs {
|
||||||
@@ -484,6 +512,14 @@ impl CommandLineArgs {
|
|||||||
pub fn env_variables(&self) -> &Vec<String> {
|
pub fn env_variables(&self) -> &Vec<String> {
|
||||||
&self.env
|
&self.env
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn tracing_filter_directives(&self) -> String {
|
||||||
|
if self.verbose {
|
||||||
|
"debug".into()
|
||||||
|
} else {
|
||||||
|
self.log_filter.clone()
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Represents the application configuration
|
/// Represents the application configuration
|
||||||
@@ -507,11 +543,11 @@ impl Config {
|
|||||||
ConfigFile::read(base_dirs, opt.config.clone()).unwrap_or_else(|e| {
|
ConfigFile::read(base_dirs, opt.config.clone()).unwrap_or_else(|e| {
|
||||||
// Inform the user about errors when loading the configuration,
|
// Inform the user about errors when loading the configuration,
|
||||||
// but fallback to the default config to at least attempt to do something
|
// but fallback to the default config to at least attempt to do something
|
||||||
log::error!("failed to load configuration: {}", e);
|
tracing::error!("failed to load configuration: {}", e);
|
||||||
ConfigFile::default()
|
ConfigFile::default()
|
||||||
})
|
})
|
||||||
} else {
|
} else {
|
||||||
log::debug!("Configuration directory {} does not exist", config_directory.display());
|
tracing::debug!("Configuration directory {} does not exist", config_directory.display());
|
||||||
ConfigFile::default()
|
ConfigFile::default()
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -626,7 +662,7 @@ impl Config {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Extra Tmux arguments
|
/// Extra Tmux arguments
|
||||||
pub fn tmux_arguments(&self) -> anyhow::Result<Vec<String>> {
|
pub fn tmux_arguments(&self) -> eyre::Result<Vec<String>> {
|
||||||
let args = &self.config_file.tmux_arguments.as_deref().unwrap_or_default();
|
let args = &self.config_file.tmux_arguments.as_deref().unwrap_or_default();
|
||||||
shell_words::split(args)
|
shell_words::split(args)
|
||||||
// The only time the parse failed is in case of a missing close quote.
|
// The only time the parse failed is in case of a missing close quote.
|
||||||
@@ -924,6 +960,12 @@ impl Config {
|
|||||||
.unwrap_or(false)
|
.unwrap_or(false)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// If `true`, `sudo` should be called after `pre_commands` in order to elevate at the
|
||||||
|
/// start of the session (and not in the middle).
|
||||||
|
pub fn pre_sudo(&self) -> bool {
|
||||||
|
self.config_file.pre_sudo.unwrap_or(false)
|
||||||
|
}
|
||||||
|
|
||||||
#[cfg(target_os = "linux")]
|
#[cfg(target_os = "linux")]
|
||||||
pub fn npm_use_sudo(&self) -> bool {
|
pub fn npm_use_sudo(&self) -> bool {
|
||||||
self.config_file
|
self.config_file
|
||||||
|
|||||||
@@ -16,6 +16,6 @@ extern "system" fn handler(ctrl_type: DWORD) -> BOOL {
|
|||||||
|
|
||||||
pub fn set_handler() {
|
pub fn set_handler() {
|
||||||
if 0 == unsafe { SetConsoleCtrlHandler(Some(handler), TRUE) } {
|
if 0 == unsafe { SetConsoleCtrlHandler(Some(handler), TRUE) } {
|
||||||
log::error!("Cannot set a control C handler")
|
tracing::error!("Cannot set a control C handler")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,11 +4,11 @@ use thiserror::Error;
|
|||||||
|
|
||||||
#[derive(Error, Debug, PartialEq, Eq)]
|
#[derive(Error, Debug, PartialEq, Eq)]
|
||||||
pub enum TopgradeError {
|
pub enum TopgradeError {
|
||||||
#[error("{0}")]
|
#[error("`{0}` failed: {1}")]
|
||||||
ProcessFailed(ExitStatus),
|
ProcessFailed(String, ExitStatus),
|
||||||
|
|
||||||
#[error("{0}: {1}")]
|
#[error("`{0}` failed: {1}")]
|
||||||
ProcessFailedWithOutput(ExitStatus, String),
|
ProcessFailedWithOutput(String, ExitStatus, String),
|
||||||
|
|
||||||
#[error("Sudo is required for this step")]
|
#[error("Sudo is required for this step")]
|
||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
|
|||||||
@@ -1,51 +1,47 @@
|
|||||||
#![allow(dead_code)]
|
#![allow(dead_code)]
|
||||||
use crate::executor::RunType;
|
use crate::executor::RunType;
|
||||||
use crate::git::Git;
|
use crate::git::Git;
|
||||||
|
use crate::sudo::Sudo;
|
||||||
use crate::utils::require_option;
|
use crate::utils::require_option;
|
||||||
use crate::{config::Config, executor::Executor};
|
use crate::{config::Config, executor::Executor};
|
||||||
use anyhow::Result;
|
use color_eyre::eyre::Result;
|
||||||
use directories::BaseDirs;
|
use directories::BaseDirs;
|
||||||
use std::path::{Path, PathBuf};
|
use std::path::Path;
|
||||||
|
use std::sync::Mutex;
|
||||||
|
|
||||||
pub struct ExecutionContext<'a> {
|
pub struct ExecutionContext<'a> {
|
||||||
run_type: RunType,
|
run_type: RunType,
|
||||||
sudo: &'a Option<PathBuf>,
|
sudo: Option<Sudo>,
|
||||||
git: &'a Git,
|
git: &'a Git,
|
||||||
config: &'a Config,
|
config: &'a Config,
|
||||||
base_dirs: &'a BaseDirs,
|
base_dirs: &'a BaseDirs,
|
||||||
|
/// Name of a tmux session to execute commands in, if any.
|
||||||
|
/// This is used in `./steps/remote/ssh.rs`, where we want to run `topgrade` in a new
|
||||||
|
/// tmux window for each remote.
|
||||||
|
tmux_session: Mutex<Option<String>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> ExecutionContext<'a> {
|
impl<'a> ExecutionContext<'a> {
|
||||||
pub fn new(
|
pub fn new(
|
||||||
run_type: RunType,
|
run_type: RunType,
|
||||||
sudo: &'a Option<PathBuf>,
|
sudo: Option<Sudo>,
|
||||||
git: &'a Git,
|
git: &'a Git,
|
||||||
config: &'a Config,
|
config: &'a Config,
|
||||||
base_dirs: &'a BaseDirs,
|
base_dirs: &'a BaseDirs,
|
||||||
) -> ExecutionContext<'a> {
|
) -> Self {
|
||||||
ExecutionContext {
|
Self {
|
||||||
run_type,
|
run_type,
|
||||||
sudo,
|
sudo,
|
||||||
git,
|
git,
|
||||||
config,
|
config,
|
||||||
base_dirs,
|
base_dirs,
|
||||||
|
tmux_session: Mutex::new(None),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn execute_elevated(&self, command: &Path, interactive: bool) -> Result<Executor> {
|
pub fn execute_elevated(&self, command: &Path, interactive: bool) -> Result<Executor> {
|
||||||
let sudo = require_option(self.sudo.clone(), "Sudo is required for this operation".into())?;
|
let sudo = require_option(self.sudo.clone(), "Sudo is required for this operation".into())?;
|
||||||
let mut cmd = self.run_type.execute(&sudo);
|
Ok(sudo.execute_elevated(self, command, interactive))
|
||||||
|
|
||||||
if sudo.ends_with("sudo") {
|
|
||||||
cmd.arg("--preserve-env=DIFFPROG");
|
|
||||||
}
|
|
||||||
|
|
||||||
if interactive {
|
|
||||||
cmd.arg("-i");
|
|
||||||
}
|
|
||||||
|
|
||||||
cmd.arg(command);
|
|
||||||
Ok(cmd)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn run_type(&self) -> RunType {
|
pub fn run_type(&self) -> RunType {
|
||||||
@@ -56,8 +52,8 @@ impl<'a> ExecutionContext<'a> {
|
|||||||
self.git
|
self.git
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn sudo(&self) -> &Option<PathBuf> {
|
pub fn sudo(&self) -> &Option<Sudo> {
|
||||||
self.sudo
|
&self.sudo
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn config(&self) -> &Config {
|
pub fn config(&self) -> &Config {
|
||||||
@@ -67,4 +63,12 @@ impl<'a> ExecutionContext<'a> {
|
|||||||
pub fn base_dirs(&self) -> &BaseDirs {
|
pub fn base_dirs(&self) -> &BaseDirs {
|
||||||
self.base_dirs
|
self.base_dirs
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn set_tmux_session(&self, session_name: String) {
|
||||||
|
self.tmux_session.lock().unwrap().replace(session_name);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_tmux_session(&self) -> Option<String> {
|
||||||
|
self.tmux_session.lock().unwrap().clone()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
147
src/executor.rs
147
src/executor.rs
@@ -1,11 +1,14 @@
|
|||||||
//! Utilities for command execution
|
//! Utilities for command execution
|
||||||
use crate::error::{DryRun, TopgradeError};
|
|
||||||
use crate::utils::{Check, CheckWithCodes};
|
|
||||||
use anyhow::Result;
|
|
||||||
use log::{debug, trace};
|
|
||||||
use std::ffi::{OsStr, OsString};
|
use std::ffi::{OsStr, OsString};
|
||||||
use std::path::Path;
|
use std::path::Path;
|
||||||
use std::process::{Child, Command, ExitStatus};
|
use std::process::{Child, Command, ExitStatus, Output};
|
||||||
|
|
||||||
|
use color_eyre::eyre;
|
||||||
|
use color_eyre::eyre::Result;
|
||||||
|
use tracing::debug;
|
||||||
|
|
||||||
|
use crate::command::CommandExt;
|
||||||
|
use crate::error::DryRun;
|
||||||
|
|
||||||
/// An enum telling whether Topgrade should perform dry runs or actually perform the steps.
|
/// An enum telling whether Topgrade should perform dry runs or actually perform the steps.
|
||||||
#[derive(Clone, Copy, Debug)]
|
#[derive(Clone, Copy, Debug)]
|
||||||
@@ -56,6 +59,16 @@ pub enum Executor {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl Executor {
|
impl Executor {
|
||||||
|
/// Get the name of the program being run.
|
||||||
|
///
|
||||||
|
/// Will give weird results for non-UTF-8 programs; see `to_string_lossy()`.
|
||||||
|
pub fn get_program(&self) -> String {
|
||||||
|
match self {
|
||||||
|
Executor::Wet(c) => c.get_program().to_string_lossy().into_owned(),
|
||||||
|
Executor::Dry(c) => c.program.to_string_lossy().into_owned(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// See `std::process::Command::arg`
|
/// See `std::process::Command::arg`
|
||||||
pub fn arg<S: AsRef<OsStr>>(&mut self, arg: S) -> &mut Executor {
|
pub fn arg<S: AsRef<OsStr>>(&mut self, arg: S) -> &mut Executor {
|
||||||
match self {
|
match self {
|
||||||
@@ -139,7 +152,7 @@ impl Executor {
|
|||||||
let result = match self {
|
let result = match self {
|
||||||
Executor::Wet(c) => {
|
Executor::Wet(c) => {
|
||||||
debug!("Running {:?}", c);
|
debug!("Running {:?}", c);
|
||||||
c.spawn().map(ExecutorChild::Wet)?
|
c.spawn_checked().map(ExecutorChild::Wet)?
|
||||||
}
|
}
|
||||||
Executor::Dry(c) => {
|
Executor::Dry(c) => {
|
||||||
c.dry_run();
|
c.dry_run();
|
||||||
@@ -153,7 +166,7 @@ impl Executor {
|
|||||||
/// See `std::process::Command::output`
|
/// See `std::process::Command::output`
|
||||||
pub fn output(&mut self) -> Result<ExecutorOutput> {
|
pub fn output(&mut self) -> Result<ExecutorOutput> {
|
||||||
match self {
|
match self {
|
||||||
Executor::Wet(c) => Ok(ExecutorOutput::Wet(c.output()?)),
|
Executor::Wet(c) => Ok(ExecutorOutput::Wet(c.output_checked()?)),
|
||||||
Executor::Dry(c) => {
|
Executor::Dry(c) => {
|
||||||
c.dry_run();
|
c.dry_run();
|
||||||
Ok(ExecutorOutput::Dry)
|
Ok(ExecutorOutput::Dry)
|
||||||
@@ -161,23 +174,28 @@ impl Executor {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A convinence method for `spawn().wait().check()`.
|
/// An extension of `status_checked` that allows you to set a sequence of codes
|
||||||
/// Returns an error if something went wrong during the execution or if the
|
|
||||||
/// process exited with failure.
|
|
||||||
pub fn check_run(&mut self) -> Result<()> {
|
|
||||||
self.spawn()?.wait()?.check()
|
|
||||||
}
|
|
||||||
|
|
||||||
/// An extension of `check_run` that allows you to set a sequence of codes
|
|
||||||
/// that can indicate success of a script
|
/// that can indicate success of a script
|
||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
pub fn check_run_with_codes(&mut self, codes: &[i32]) -> Result<()> {
|
pub fn status_checked_with_codes(&mut self, codes: &[i32]) -> Result<()> {
|
||||||
self.spawn()?.wait()?.check_with_codes(codes)
|
match self {
|
||||||
|
Executor::Wet(c) => c.status_checked_with(|status| {
|
||||||
|
if status.success() || status.code().as_ref().map(|c| codes.contains(c)).unwrap_or(false) {
|
||||||
|
Ok(())
|
||||||
|
} else {
|
||||||
|
Err(())
|
||||||
|
}
|
||||||
|
}),
|
||||||
|
Executor::Dry(c) => {
|
||||||
|
c.dry_run();
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub enum ExecutorOutput {
|
pub enum ExecutorOutput {
|
||||||
Wet(std::process::Output),
|
Wet(Output),
|
||||||
Dry,
|
Dry,
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -214,78 +232,33 @@ pub enum ExecutorChild {
|
|||||||
Dry,
|
Dry,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ExecutorChild {
|
|
||||||
/// See `std::process::Child::wait`
|
|
||||||
pub fn wait(&mut self) -> Result<ExecutorExitStatus> {
|
|
||||||
let result = match self {
|
|
||||||
ExecutorChild::Wet(c) => c.wait().map(ExecutorExitStatus::Wet)?,
|
|
||||||
ExecutorChild::Dry => ExecutorExitStatus::Dry,
|
|
||||||
};
|
|
||||||
|
|
||||||
Ok(result)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// The Result of wait. Contains an actual `std::process::ExitStatus` if executed by a wet command.
|
|
||||||
pub enum ExecutorExitStatus {
|
|
||||||
Wet(ExitStatus),
|
|
||||||
Dry,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl CheckWithCodes for ExecutorExitStatus {
|
|
||||||
fn check_with_codes(self, codes: &[i32]) -> Result<()> {
|
|
||||||
match self {
|
|
||||||
ExecutorExitStatus::Wet(e) => e.check_with_codes(codes),
|
|
||||||
ExecutorExitStatus::Dry => Ok(()),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Extension methods for `std::process::Command`
|
|
||||||
pub trait CommandExt {
|
|
||||||
/// Run the command, wait for it to complete, check the return code and decode the output as UTF-8.
|
|
||||||
fn check_output(&mut self) -> Result<String>;
|
|
||||||
fn string_output(&mut self) -> Result<String>;
|
|
||||||
}
|
|
||||||
|
|
||||||
impl CommandExt for Command {
|
|
||||||
fn check_output(&mut self) -> Result<String> {
|
|
||||||
let output = self.output()?;
|
|
||||||
trace!("Output of {:?}: {:?}", self, output);
|
|
||||||
let status = output.status;
|
|
||||||
if !status.success() {
|
|
||||||
let stderr = String::from_utf8(output.stderr).unwrap_or_default();
|
|
||||||
return Err(TopgradeError::ProcessFailedWithOutput(status, stderr).into());
|
|
||||||
}
|
|
||||||
Ok(String::from_utf8(output.stdout)?)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn string_output(&mut self) -> Result<String> {
|
|
||||||
let output = self.output()?;
|
|
||||||
trace!("Output of {:?}: {:?}", self, output);
|
|
||||||
Ok(String::from_utf8(output.stdout)?)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl CommandExt for Executor {
|
impl CommandExt for Executor {
|
||||||
fn check_output(&mut self) -> Result<String> {
|
type Child = ExecutorChild;
|
||||||
let output = match self.output()? {
|
|
||||||
ExecutorOutput::Wet(output) => output,
|
// TODO: It might be nice to make `output_checked_with` return something that has a
|
||||||
ExecutorOutput::Dry => return Err(DryRun().into()),
|
// variant for wet/dry runs.
|
||||||
};
|
|
||||||
let status = output.status;
|
fn output_checked_with(&mut self, succeeded: impl Fn(&Output) -> Result<(), ()>) -> eyre::Result<Output> {
|
||||||
if !status.success() {
|
match self {
|
||||||
let stderr = String::from_utf8(output.stderr).unwrap_or_default();
|
Executor::Wet(c) => c.output_checked_with(succeeded),
|
||||||
return Err(TopgradeError::ProcessFailedWithOutput(status, stderr).into());
|
Executor::Dry(c) => {
|
||||||
|
c.dry_run();
|
||||||
|
Err(DryRun().into())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
Ok(String::from_utf8(output.stdout)?)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn string_output(&mut self) -> Result<String> {
|
fn status_checked_with(&mut self, succeeded: impl Fn(ExitStatus) -> Result<(), ()>) -> eyre::Result<()> {
|
||||||
let output = match self.output()? {
|
match self {
|
||||||
ExecutorOutput::Wet(output) => output,
|
Executor::Wet(c) => c.status_checked_with(succeeded),
|
||||||
ExecutorOutput::Dry => return Err(DryRun().into()),
|
Executor::Dry(c) => {
|
||||||
};
|
c.dry_run();
|
||||||
Ok(String::from_utf8(output.stdout)?)
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn spawn_checked(&mut self) -> eyre::Result<Self::Child> {
|
||||||
|
self.spawn()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
106
src/main.rs
106
src/main.rs
@@ -4,12 +4,12 @@ use std::env;
|
|||||||
use std::io;
|
use std::io;
|
||||||
use std::process::exit;
|
use std::process::exit;
|
||||||
|
|
||||||
use anyhow::{anyhow, Result};
|
use clap::CommandFactory;
|
||||||
use clap::{crate_version, Parser};
|
use clap::{crate_version, Parser};
|
||||||
|
use color_eyre::eyre::Context;
|
||||||
|
use color_eyre::eyre::{eyre, Result};
|
||||||
use console::Key;
|
use console::Key;
|
||||||
use log::debug;
|
use tracing::debug;
|
||||||
use log::LevelFilter;
|
|
||||||
use pretty_env_logger::formatted_timed_builder;
|
|
||||||
|
|
||||||
use self::config::{CommandLineArgs, Config, Step};
|
use self::config::{CommandLineArgs, Config, Step};
|
||||||
use self::error::StepFailed;
|
use self::error::StepFailed;
|
||||||
@@ -18,6 +18,7 @@ use self::error::Upgraded;
|
|||||||
use self::steps::{remote::*, *};
|
use self::steps::{remote::*, *};
|
||||||
use self::terminal::*;
|
use self::terminal::*;
|
||||||
|
|
||||||
|
mod command;
|
||||||
mod config;
|
mod config;
|
||||||
mod ctrlc;
|
mod ctrlc;
|
||||||
mod error;
|
mod error;
|
||||||
@@ -30,16 +31,32 @@ mod self_renamer;
|
|||||||
#[cfg(feature = "self-update")]
|
#[cfg(feature = "self-update")]
|
||||||
mod self_update;
|
mod self_update;
|
||||||
mod steps;
|
mod steps;
|
||||||
|
mod sudo;
|
||||||
mod terminal;
|
mod terminal;
|
||||||
mod utils;
|
mod utils;
|
||||||
|
|
||||||
fn run() -> Result<()> {
|
fn run() -> Result<()> {
|
||||||
|
color_eyre::install()?;
|
||||||
ctrlc::set_handler();
|
ctrlc::set_handler();
|
||||||
|
|
||||||
let base_dirs = directories::BaseDirs::new().ok_or_else(|| anyhow!("No base directories"))?;
|
let base_dirs = directories::BaseDirs::new().ok_or_else(|| eyre!("No base directories"))?;
|
||||||
|
|
||||||
let opt = CommandLineArgs::parse();
|
let opt = CommandLineArgs::parse();
|
||||||
|
|
||||||
|
if let Some(shell) = opt.gen_completion {
|
||||||
|
let cmd = &mut CommandLineArgs::command();
|
||||||
|
clap_complete::generate(shell, cmd, clap::crate_name!(), &mut std::io::stdout());
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
|
||||||
|
if opt.gen_manpage {
|
||||||
|
let man = clap_mangen::Man::new(CommandLineArgs::command());
|
||||||
|
man.render(&mut std::io::stdout())?;
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
|
||||||
|
install_tracing(&opt.tracing_filter_directives())?;
|
||||||
|
|
||||||
for env in opt.env_variables() {
|
for env in opt.env_variables() {
|
||||||
let mut splitted = env.split('=');
|
let mut splitted = env.split('=');
|
||||||
let var = splitted.next().unwrap();
|
let var = splitted.next().unwrap();
|
||||||
@@ -47,14 +64,6 @@ fn run() -> Result<()> {
|
|||||||
env::set_var(var, value);
|
env::set_var(var, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut builder = formatted_timed_builder();
|
|
||||||
|
|
||||||
if opt.verbose {
|
|
||||||
builder.filter(Some("topgrade"), LevelFilter::Trace);
|
|
||||||
}
|
|
||||||
|
|
||||||
builder.init();
|
|
||||||
|
|
||||||
if opt.edit_config() {
|
if opt.edit_config() {
|
||||||
Config::edit(&base_dirs)?;
|
Config::edit(&base_dirs)?;
|
||||||
return Ok(());
|
return Ok(());
|
||||||
@@ -79,17 +88,18 @@ fn run() -> Result<()> {
|
|||||||
if config.run_in_tmux() && env::var("TOPGRADE_INSIDE_TMUX").is_err() {
|
if config.run_in_tmux() && env::var("TOPGRADE_INSIDE_TMUX").is_err() {
|
||||||
#[cfg(unix)]
|
#[cfg(unix)]
|
||||||
{
|
{
|
||||||
tmux::run_in_tmux(config.tmux_arguments()?);
|
tmux::run_in_tmux(config.tmux_arguments()?)?;
|
||||||
|
return Ok(());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let git = git::Git::new();
|
let git = git::Git::new();
|
||||||
let mut git_repos = git::Repositories::new(&git);
|
let mut git_repos = git::Repositories::new(&git);
|
||||||
|
|
||||||
let sudo = utils::sudo();
|
let sudo = sudo::Sudo::detect();
|
||||||
let run_type = executor::RunType::new(config.dry_run());
|
let run_type = executor::RunType::new(config.dry_run());
|
||||||
|
|
||||||
let ctx = execution_context::ExecutionContext::new(run_type, &sudo, &git, &config, &base_dirs);
|
let ctx = execution_context::ExecutionContext::new(run_type, sudo, &git, &config, &base_dirs);
|
||||||
|
|
||||||
let mut runner = runner::Runner::new(&ctx);
|
let mut runner = runner::Runner::new(&ctx);
|
||||||
|
|
||||||
@@ -123,6 +133,12 @@ fn run() -> Result<()> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if config.pre_sudo() {
|
||||||
|
if let Some(sudo) = ctx.sudo() {
|
||||||
|
sudo.elevate(&ctx)?;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
let powershell = powershell::Powershell::new();
|
let powershell = powershell::Powershell::new();
|
||||||
let should_run_powershell = powershell.profile().is_some() && config.should_run(Step::Powershell);
|
let should_run_powershell = powershell.profile().is_some() && config.should_run(Step::Powershell);
|
||||||
|
|
||||||
@@ -201,17 +217,17 @@ fn run() -> Result<()> {
|
|||||||
|
|
||||||
#[cfg(target_os = "dragonfly")]
|
#[cfg(target_os = "dragonfly")]
|
||||||
runner.execute(Step::Pkg, "DragonFly BSD Packages", || {
|
runner.execute(Step::Pkg, "DragonFly BSD Packages", || {
|
||||||
dragonfly::upgrade_packages(sudo.as_ref(), run_type)
|
dragonfly::upgrade_packages(ctx.sudo().as_ref(), run_type)
|
||||||
})?;
|
})?;
|
||||||
|
|
||||||
#[cfg(target_os = "freebsd")]
|
#[cfg(target_os = "freebsd")]
|
||||||
runner.execute(Step::Pkg, "FreeBSD Packages", || {
|
runner.execute(Step::Pkg, "FreeBSD Packages", || {
|
||||||
freebsd::upgrade_packages(sudo.as_ref(), run_type)
|
freebsd::upgrade_packages(&ctx, ctx.sudo().as_ref(), run_type)
|
||||||
})?;
|
})?;
|
||||||
|
|
||||||
#[cfg(target_os = "openbsd")]
|
#[cfg(target_os = "openbsd")]
|
||||||
runner.execute(Step::Pkg, "OpenBSD Packages", || {
|
runner.execute(Step::Pkg, "OpenBSD Packages", || {
|
||||||
openbsd::upgrade_packages(sudo.as_ref(), run_type)
|
openbsd::upgrade_packages(ctx.sudo().as_ref(), run_type)
|
||||||
})?;
|
})?;
|
||||||
|
|
||||||
#[cfg(target_os = "android")]
|
#[cfg(target_os = "android")]
|
||||||
@@ -296,7 +312,7 @@ fn run() -> Result<()> {
|
|||||||
runner.execute(Step::Shell, "zi", || zsh::run_zi(&base_dirs, run_type))?;
|
runner.execute(Step::Shell, "zi", || zsh::run_zi(&base_dirs, run_type))?;
|
||||||
runner.execute(Step::Shell, "zim", || zsh::run_zim(&base_dirs, run_type))?;
|
runner.execute(Step::Shell, "zim", || zsh::run_zim(&base_dirs, run_type))?;
|
||||||
runner.execute(Step::Shell, "oh-my-zsh", || zsh::run_oh_my_zsh(&ctx))?;
|
runner.execute(Step::Shell, "oh-my-zsh", || zsh::run_oh_my_zsh(&ctx))?;
|
||||||
runner.execute(Step::Shell, "fisher", || unix::run_fisher(&base_dirs, run_type))?;
|
runner.execute(Step::Shell, "fisher", || unix::run_fisher(run_type))?;
|
||||||
runner.execute(Step::Shell, "bash-it", || unix::run_bashit(&ctx))?;
|
runner.execute(Step::Shell, "bash-it", || unix::run_bashit(&ctx))?;
|
||||||
runner.execute(Step::Shell, "oh-my-fish", || unix::run_oh_my_fish(&ctx))?;
|
runner.execute(Step::Shell, "oh-my-fish", || unix::run_oh_my_fish(&ctx))?;
|
||||||
runner.execute(Step::Shell, "fish-plug", || unix::run_fish_plug(&ctx))?;
|
runner.execute(Step::Shell, "fish-plug", || unix::run_fish_plug(&ctx))?;
|
||||||
@@ -323,11 +339,13 @@ fn run() -> Result<()> {
|
|||||||
runner.execute(Step::Atom, "apm", || generic::run_apm(run_type))?;
|
runner.execute(Step::Atom, "apm", || generic::run_apm(run_type))?;
|
||||||
runner.execute(Step::Fossil, "fossil", || generic::run_fossil(run_type))?;
|
runner.execute(Step::Fossil, "fossil", || generic::run_fossil(run_type))?;
|
||||||
runner.execute(Step::Rustup, "rustup", || generic::run_rustup(&base_dirs, run_type))?;
|
runner.execute(Step::Rustup, "rustup", || generic::run_rustup(&base_dirs, run_type))?;
|
||||||
|
runner.execute(Step::Juliaup, "juliaup", || generic::run_juliaup(&base_dirs, run_type))?;
|
||||||
runner.execute(Step::Dotnet, ".NET", || generic::run_dotnet_upgrade(&ctx))?;
|
runner.execute(Step::Dotnet, ".NET", || generic::run_dotnet_upgrade(&ctx))?;
|
||||||
runner.execute(Step::Choosenim, "choosenim", || generic::run_choosenim(&ctx))?;
|
runner.execute(Step::Choosenim, "choosenim", || generic::run_choosenim(&ctx))?;
|
||||||
runner.execute(Step::Cargo, "cargo", || generic::run_cargo_update(&ctx))?;
|
runner.execute(Step::Cargo, "cargo", || generic::run_cargo_update(&ctx))?;
|
||||||
runner.execute(Step::Flutter, "Flutter", || generic::run_flutter_upgrade(run_type))?;
|
runner.execute(Step::Flutter, "Flutter", || generic::run_flutter_upgrade(run_type))?;
|
||||||
runner.execute(Step::Go, "Go", || generic::run_go(run_type))?;
|
runner.execute(Step::Go, "go-global-update", || go::run_go_global_update(run_type))?;
|
||||||
|
runner.execute(Step::Go, "gup", || go::run_go_gup(run_type))?;
|
||||||
runner.execute(Step::Emacs, "Emacs", || emacs.upgrade(&ctx))?;
|
runner.execute(Step::Emacs, "Emacs", || emacs.upgrade(&ctx))?;
|
||||||
runner.execute(Step::Opam, "opam", || generic::run_opam_update(&ctx))?;
|
runner.execute(Step::Opam, "opam", || generic::run_opam_update(&ctx))?;
|
||||||
runner.execute(Step::Vcpkg, "vcpkg", || generic::run_vcpkg_update(run_type))?;
|
runner.execute(Step::Vcpkg, "vcpkg", || generic::run_vcpkg_update(run_type))?;
|
||||||
@@ -357,6 +375,9 @@ fn run() -> Result<()> {
|
|||||||
runner.execute(Step::Composer, "composer", || generic::run_composer_update(&ctx))?;
|
runner.execute(Step::Composer, "composer", || generic::run_composer_update(&ctx))?;
|
||||||
runner.execute(Step::Krew, "krew", || generic::run_krew_upgrade(run_type))?;
|
runner.execute(Step::Krew, "krew", || generic::run_krew_upgrade(run_type))?;
|
||||||
runner.execute(Step::Gem, "gem", || generic::run_gem(&base_dirs, run_type))?;
|
runner.execute(Step::Gem, "gem", || generic::run_gem(&base_dirs, run_type))?;
|
||||||
|
runner.execute(Step::RubyGems, "rubygems", || {
|
||||||
|
generic::run_rubygems(&base_dirs, run_type)
|
||||||
|
})?;
|
||||||
runner.execute(Step::Julia, "julia", || generic::update_julia_packages(&ctx))?;
|
runner.execute(Step::Julia, "julia", || generic::update_julia_packages(&ctx))?;
|
||||||
runner.execute(Step::Haxelib, "haxelib", || generic::run_haxelib_update(&ctx))?;
|
runner.execute(Step::Haxelib, "haxelib", || generic::run_haxelib_update(&ctx))?;
|
||||||
runner.execute(Step::Sheldon, "sheldon", || generic::run_sheldon(&ctx))?;
|
runner.execute(Step::Sheldon, "sheldon", || generic::run_sheldon(&ctx))?;
|
||||||
@@ -377,7 +398,7 @@ fn run() -> Result<()> {
|
|||||||
runner.execute(Step::DebGet, "deb-get", || linux::run_deb_get(&ctx))?;
|
runner.execute(Step::DebGet, "deb-get", || linux::run_deb_get(&ctx))?;
|
||||||
runner.execute(Step::Toolbx, "toolbx", || toolbx::run_toolbx(&ctx))?;
|
runner.execute(Step::Toolbx, "toolbx", || toolbx::run_toolbx(&ctx))?;
|
||||||
runner.execute(Step::Flatpak, "Flatpak", || linux::flatpak_update(&ctx))?;
|
runner.execute(Step::Flatpak, "Flatpak", || linux::flatpak_update(&ctx))?;
|
||||||
runner.execute(Step::Snap, "snap", || linux::run_snap(sudo.as_ref(), run_type))?;
|
runner.execute(Step::Snap, "snap", || linux::run_snap(ctx.sudo().as_ref(), run_type))?;
|
||||||
runner.execute(Step::Pacstall, "pacstall", || linux::run_pacstall(&ctx))?;
|
runner.execute(Step::Pacstall, "pacstall", || linux::run_pacstall(&ctx))?;
|
||||||
runner.execute(Step::Pacdef, "pacdef", || linux::run_pacdef(&ctx))?;
|
runner.execute(Step::Pacdef, "pacdef", || linux::run_pacdef(&ctx))?;
|
||||||
runner.execute(Step::Protonup, "protonup", || linux::run_protonup_update(&ctx))?;
|
runner.execute(Step::Protonup, "protonup", || linux::run_protonup_update(&ctx))?;
|
||||||
@@ -397,11 +418,11 @@ fn run() -> Result<()> {
|
|||||||
#[cfg(target_os = "linux")]
|
#[cfg(target_os = "linux")]
|
||||||
{
|
{
|
||||||
runner.execute(Step::System, "pihole", || {
|
runner.execute(Step::System, "pihole", || {
|
||||||
linux::run_pihole_update(sudo.as_ref(), run_type)
|
linux::run_pihole_update(ctx.sudo().as_ref(), run_type)
|
||||||
})?;
|
})?;
|
||||||
runner.execute(Step::Firmware, "Firmware upgrades", || linux::run_fwupdmgr(&ctx))?;
|
runner.execute(Step::Firmware, "Firmware upgrades", || linux::run_fwupdmgr(&ctx))?;
|
||||||
runner.execute(Step::Restarts, "Restarts", || {
|
runner.execute(Step::Restarts, "Restarts", || {
|
||||||
linux::run_needrestart(sudo.as_ref(), run_type)
|
linux::run_needrestart(ctx.sudo().as_ref(), run_type)
|
||||||
})?;
|
})?;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -414,12 +435,12 @@ fn run() -> Result<()> {
|
|||||||
|
|
||||||
#[cfg(target_os = "freebsd")]
|
#[cfg(target_os = "freebsd")]
|
||||||
runner.execute(Step::System, "FreeBSD Upgrade", || {
|
runner.execute(Step::System, "FreeBSD Upgrade", || {
|
||||||
freebsd::upgrade_freebsd(sudo.as_ref(), run_type)
|
freebsd::upgrade_freebsd(ctx.sudo().as_ref(), run_type)
|
||||||
})?;
|
})?;
|
||||||
|
|
||||||
#[cfg(target_os = "openbsd")]
|
#[cfg(target_os = "openbsd")]
|
||||||
runner.execute(Step::System, "OpenBSD Upgrade", || {
|
runner.execute(Step::System, "OpenBSD Upgrade", || {
|
||||||
openbsd::upgrade_openbsd(sudo.as_ref(), run_type)
|
openbsd::upgrade_openbsd(ctx.sudo().as_ref(), run_type)
|
||||||
})?;
|
})?;
|
||||||
|
|
||||||
#[cfg(windows)]
|
#[cfg(windows)]
|
||||||
@@ -451,10 +472,10 @@ fn run() -> Result<()> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(target_os = "freebsd")]
|
#[cfg(target_os = "freebsd")]
|
||||||
freebsd::audit_packages(&sudo).ok();
|
freebsd::audit_packages(ctx.sudo().as_ref()).ok();
|
||||||
|
|
||||||
#[cfg(target_os = "dragonfly")]
|
#[cfg(target_os = "dragonfly")]
|
||||||
dragonfly::audit_packages(&sudo).ok();
|
dragonfly::audit_packages(ctx.sudo().as_ref()).ok();
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut post_command_failed = false;
|
let mut post_command_failed = false;
|
||||||
@@ -471,10 +492,10 @@ fn run() -> Result<()> {
|
|||||||
loop {
|
loop {
|
||||||
match get_key() {
|
match get_key() {
|
||||||
Ok(Key::Char('s')) | Ok(Key::Char('S')) => {
|
Ok(Key::Char('s')) | Ok(Key::Char('S')) => {
|
||||||
run_shell();
|
run_shell().context("Failed to execute shell")?;
|
||||||
}
|
}
|
||||||
Ok(Key::Char('r')) | Ok(Key::Char('R')) => {
|
Ok(Key::Char('r')) | Ok(Key::Char('R')) => {
|
||||||
reboot();
|
reboot().context("Failed to reboot")?;
|
||||||
}
|
}
|
||||||
Ok(Key::Char('q')) | Ok(Key::Char('Q')) => (),
|
Ok(Key::Char('q')) | Ok(Key::Char('Q')) => (),
|
||||||
_ => {
|
_ => {
|
||||||
@@ -524,7 +545,7 @@ fn main() {
|
|||||||
.is_some());
|
.is_some());
|
||||||
|
|
||||||
if !skip_print {
|
if !skip_print {
|
||||||
// The `Debug` implementation of `anyhow::Result` prints a multi-line
|
// The `Debug` implementation of `eyre::Result` prints a multi-line
|
||||||
// error message that includes all the 'causes' added with
|
// error message that includes all the 'causes' added with
|
||||||
// `.with_context(...)` calls.
|
// `.with_context(...)` calls.
|
||||||
println!("Error: {:?}", error);
|
println!("Error: {:?}", error);
|
||||||
@@ -533,3 +554,26 @@ fn main() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn install_tracing(filter_directives: &str) -> Result<()> {
|
||||||
|
use tracing_subscriber::fmt;
|
||||||
|
use tracing_subscriber::fmt::format::FmtSpan;
|
||||||
|
use tracing_subscriber::layer::SubscriberExt;
|
||||||
|
use tracing_subscriber::util::SubscriberInitExt;
|
||||||
|
use tracing_subscriber::EnvFilter;
|
||||||
|
|
||||||
|
let env_filter = EnvFilter::try_new(filter_directives)
|
||||||
|
.or_else(|_| EnvFilter::try_from_default_env())
|
||||||
|
.or_else(|_| EnvFilter::try_new("info"))?;
|
||||||
|
|
||||||
|
let fmt_layer = fmt::layer()
|
||||||
|
.with_target(false)
|
||||||
|
.with_span_events(FmtSpan::NEW | FmtSpan::CLOSE)
|
||||||
|
.without_time();
|
||||||
|
|
||||||
|
let registry = tracing_subscriber::registry();
|
||||||
|
|
||||||
|
registry.with(env_filter).with(fmt_layer).init();
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|||||||
@@ -2,11 +2,12 @@ use crate::ctrlc;
|
|||||||
use crate::error::{DryRun, SkipStep};
|
use crate::error::{DryRun, SkipStep};
|
||||||
use crate::execution_context::ExecutionContext;
|
use crate::execution_context::ExecutionContext;
|
||||||
use crate::report::{Report, StepResult};
|
use crate::report::{Report, StepResult};
|
||||||
|
use crate::terminal::print_error;
|
||||||
use crate::{config::Step, terminal::should_retry};
|
use crate::{config::Step, terminal::should_retry};
|
||||||
use anyhow::Result;
|
use color_eyre::eyre::Result;
|
||||||
use log::debug;
|
|
||||||
use std::borrow::Cow;
|
use std::borrow::Cow;
|
||||||
use std::fmt::Debug;
|
use std::fmt::Debug;
|
||||||
|
use tracing::debug;
|
||||||
|
|
||||||
pub struct Runner<'a> {
|
pub struct Runner<'a> {
|
||||||
ctx: &'a ExecutionContext<'a>,
|
ctx: &'a ExecutionContext<'a>,
|
||||||
@@ -55,7 +56,12 @@ impl<'a> Runner<'a> {
|
|||||||
|
|
||||||
let ignore_failure = self.ctx.config().ignore_failure(step);
|
let ignore_failure = self.ctx.config().ignore_failure(step);
|
||||||
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 = should_ask && should_retry(interrupted, key.as_ref())?;
|
let should_retry = if should_ask {
|
||||||
|
print_error(&key, format!("{e:?}"));
|
||||||
|
should_retry(interrupted, key.as_ref())?
|
||||||
|
} else {
|
||||||
|
false
|
||||||
|
};
|
||||||
|
|
||||||
if !should_retry {
|
if !should_retry {
|
||||||
self.report.push_result(Some((
|
self.report.push_result(Some((
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
#![cfg(windows)]
|
#![cfg(windows)]
|
||||||
|
|
||||||
use anyhow::Result;
|
use color_eyre::eyre::Result;
|
||||||
use log::{debug, error};
|
|
||||||
use std::{env::current_exe, fs, path::PathBuf};
|
use std::{env::current_exe, fs, path::PathBuf};
|
||||||
|
use tracing::{debug, error};
|
||||||
|
|
||||||
pub struct SelfRenamer {
|
pub struct SelfRenamer {
|
||||||
exe_path: PathBuf,
|
exe_path: PathBuf,
|
||||||
|
|||||||
@@ -1,13 +1,15 @@
|
|||||||
|
use std::env;
|
||||||
|
#[cfg(unix)]
|
||||||
|
use std::os::unix::process::CommandExt as _;
|
||||||
|
use std::process::Command;
|
||||||
|
|
||||||
|
use color_eyre::eyre::{bail, Result};
|
||||||
|
use self_update_crate::backends::github::Update;
|
||||||
|
use self_update_crate::update::UpdateStatus;
|
||||||
|
|
||||||
use super::terminal::*;
|
use super::terminal::*;
|
||||||
#[cfg(windows)]
|
#[cfg(windows)]
|
||||||
use crate::error::Upgraded;
|
use crate::error::Upgraded;
|
||||||
use anyhow::{bail, Result};
|
|
||||||
use self_update_crate::backends::github::Update;
|
|
||||||
use self_update_crate::update::UpdateStatus;
|
|
||||||
use std::env;
|
|
||||||
#[cfg(unix)]
|
|
||||||
use std::os::unix::process::CommandExt;
|
|
||||||
use std::process::Command;
|
|
||||||
|
|
||||||
pub fn self_update() -> Result<()> {
|
pub fn self_update() -> Result<()> {
|
||||||
print_separator("Self update");
|
print_separator("Self update");
|
||||||
@@ -18,11 +20,7 @@ pub fn self_update() -> Result<()> {
|
|||||||
.repo_owner("topgrade-rs")
|
.repo_owner("topgrade-rs")
|
||||||
.repo_name("topgrade")
|
.repo_name("topgrade")
|
||||||
.target(target)
|
.target(target)
|
||||||
.bin_name(if cfg!(windows) {
|
.bin_name(if cfg!(windows) { "topgrade.exe" } else { "topgrade" })
|
||||||
"topgrade-rs.exe"
|
|
||||||
} else {
|
|
||||||
"topgrade-rs"
|
|
||||||
})
|
|
||||||
.show_output(false)
|
.show_output(false)
|
||||||
.show_download_progress(true)
|
.show_download_progress(true)
|
||||||
.current_version(self_update_crate::cargo_crate_version!())
|
.current_version(self_update_crate::cargo_crate_version!())
|
||||||
@@ -53,7 +51,8 @@ pub fn self_update() -> Result<()> {
|
|||||||
|
|
||||||
#[cfg(windows)]
|
#[cfg(windows)]
|
||||||
{
|
{
|
||||||
let status = command.spawn().and_then(|mut c| c.wait())?;
|
#[allow(clippy::disallowed_methods)]
|
||||||
|
let status = command.status()?;
|
||||||
bail!(Upgraded(status));
|
bail!(Upgraded(status));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,13 +1,16 @@
|
|||||||
use anyhow::Result;
|
|
||||||
|
|
||||||
use crate::error::{self, TopgradeError};
|
|
||||||
use crate::executor::CommandExt;
|
|
||||||
use crate::terminal::print_separator;
|
|
||||||
use crate::{execution_context::ExecutionContext, utils::require};
|
|
||||||
use log::{debug, error, warn};
|
|
||||||
use std::path::Path;
|
use std::path::Path;
|
||||||
use std::process::Command;
|
use std::process::Command;
|
||||||
|
|
||||||
|
use color_eyre::eyre::eyre;
|
||||||
|
use color_eyre::eyre::Context;
|
||||||
|
use color_eyre::eyre::Result;
|
||||||
|
use tracing::{debug, error, warn};
|
||||||
|
|
||||||
|
use crate::command::CommandExt;
|
||||||
|
use crate::error::{self, TopgradeError};
|
||||||
|
use crate::terminal::print_separator;
|
||||||
|
use crate::{execution_context::ExecutionContext, utils::require};
|
||||||
|
|
||||||
// A string found in the output of docker for containers that weren't found in
|
// A string found in the output of docker for containers that weren't found in
|
||||||
// the docker registry. We use this to gracefully handle and skip containers
|
// the docker registry. We use this to gracefully handle and skip containers
|
||||||
// that cannot be pulled, likely because they don't exist in the registry in
|
// that cannot be pulled, likely because they don't exist in the registry in
|
||||||
@@ -24,11 +27,10 @@ fn list_containers(crt: &Path) -> Result<Vec<String>> {
|
|||||||
);
|
);
|
||||||
let output = Command::new(crt)
|
let output = Command::new(crt)
|
||||||
.args(["image", "ls", "--format", "{{.Repository}}:{{.Tag}}"])
|
.args(["image", "ls", "--format", "{{.Repository}}:{{.Tag}}"])
|
||||||
.output()?;
|
.output_checked_with_utf8(|_| Ok(()))?;
|
||||||
let output_str = String::from_utf8(output.stdout)?;
|
|
||||||
|
|
||||||
let mut retval = vec![];
|
let mut retval = vec![];
|
||||||
for line in output_str.lines() {
|
for line in output.stdout.lines() {
|
||||||
if line.starts_with("localhost") {
|
if line.starts_with("localhost") {
|
||||||
// Don't know how to update self-built containers
|
// Don't know how to update self-built containers
|
||||||
debug!("Skipping self-built container '{}'", line);
|
debug!("Skipping self-built container '{}'", line);
|
||||||
@@ -60,7 +62,7 @@ pub fn run_containers(ctx: &ExecutionContext) -> Result<()> {
|
|||||||
|
|
||||||
print_separator("Containers");
|
print_separator("Containers");
|
||||||
let mut success = true;
|
let mut success = true;
|
||||||
let containers = list_containers(&crt)?;
|
let containers = list_containers(&crt).context("Failed to list Docker containers")?;
|
||||||
debug!("Containers to inspect: {:?}", containers);
|
debug!("Containers to inspect: {:?}", containers);
|
||||||
|
|
||||||
for container in containers.iter() {
|
for container in containers.iter() {
|
||||||
@@ -68,7 +70,7 @@ pub fn run_containers(ctx: &ExecutionContext) -> Result<()> {
|
|||||||
let args = vec!["pull", &container[..]];
|
let args = vec!["pull", &container[..]];
|
||||||
let mut exec = ctx.run_type().execute(&crt);
|
let mut exec = ctx.run_type().execute(&crt);
|
||||||
|
|
||||||
if let Err(e) = exec.args(&args).check_run() {
|
if let Err(e) = exec.args(&args).status_checked() {
|
||||||
error!("Pulling container '{}' failed: {}", container, e);
|
error!("Pulling container '{}' failed: {}", container, e);
|
||||||
|
|
||||||
// Find out if this is 'skippable'
|
// Find out if this is 'skippable'
|
||||||
@@ -77,10 +79,10 @@ pub fn run_containers(ctx: &ExecutionContext) -> Result<()> {
|
|||||||
// practical consequence that all containers, whether self-built, created by
|
// practical consequence that all containers, whether self-built, created by
|
||||||
// docker-compose or pulled from the docker hub, look exactly the same to us. We can
|
// docker-compose or pulled from the docker hub, look exactly the same to us. We can
|
||||||
// only find out what went wrong by manually parsing the output of the command...
|
// only find out what went wrong by manually parsing the output of the command...
|
||||||
if match exec.check_output() {
|
if match exec.output_checked_utf8() {
|
||||||
Ok(s) => s.contains(NONEXISTENT_REPO),
|
Ok(s) => s.stdout.contains(NONEXISTENT_REPO) || s.stderr.contains(NONEXISTENT_REPO),
|
||||||
Err(e) => match e.downcast_ref::<TopgradeError>() {
|
Err(e) => match e.downcast_ref::<TopgradeError>() {
|
||||||
Some(TopgradeError::ProcessFailedWithOutput(_, stderr)) => stderr.contains(NONEXISTENT_REPO),
|
Some(TopgradeError::ProcessFailedWithOutput(_, _, stderr)) => stderr.contains(NONEXISTENT_REPO),
|
||||||
_ => false,
|
_ => false,
|
||||||
},
|
},
|
||||||
} {
|
} {
|
||||||
@@ -95,7 +97,12 @@ pub fn run_containers(ctx: &ExecutionContext) -> Result<()> {
|
|||||||
if ctx.config().cleanup() {
|
if ctx.config().cleanup() {
|
||||||
// Remove dangling images
|
// Remove dangling images
|
||||||
debug!("Removing dangling images");
|
debug!("Removing dangling images");
|
||||||
if let Err(e) = ctx.run_type().execute(&crt).args(["image", "prune", "-f"]).check_run() {
|
if let Err(e) = ctx
|
||||||
|
.run_type()
|
||||||
|
.execute(&crt)
|
||||||
|
.args(["image", "prune", "-f"])
|
||||||
|
.status_checked()
|
||||||
|
{
|
||||||
error!("Removing dangling images failed: {}", e);
|
error!("Removing dangling images failed: {}", e);
|
||||||
success = false;
|
success = false;
|
||||||
}
|
}
|
||||||
@@ -104,6 +111,6 @@ pub fn run_containers(ctx: &ExecutionContext) -> Result<()> {
|
|||||||
if success {
|
if success {
|
||||||
Ok(())
|
Ok(())
|
||||||
} else {
|
} else {
|
||||||
Err(anyhow::anyhow!(error::StepFailed))
|
Err(eyre!(error::StepFailed))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,9 +2,10 @@
|
|||||||
use std::env;
|
use std::env;
|
||||||
use std::path::{Path, PathBuf};
|
use std::path::{Path, PathBuf};
|
||||||
|
|
||||||
use anyhow::Result;
|
use color_eyre::eyre::Result;
|
||||||
use directories::BaseDirs;
|
use directories::BaseDirs;
|
||||||
|
|
||||||
|
use crate::command::CommandExt;
|
||||||
use crate::execution_context::ExecutionContext;
|
use crate::execution_context::ExecutionContext;
|
||||||
use crate::terminal::print_separator;
|
use crate::terminal::print_separator;
|
||||||
use crate::utils::{require, require_option, PathExt};
|
use crate::utils::{require, require_option, PathExt};
|
||||||
@@ -73,7 +74,7 @@ impl Emacs {
|
|||||||
|
|
||||||
command.args(["upgrade"]);
|
command.args(["upgrade"]);
|
||||||
|
|
||||||
command.check_run()
|
command.status_checked()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn upgrade(&self, ctx: &ExecutionContext) -> Result<()> {
|
pub fn upgrade(&self, ctx: &ExecutionContext) -> Result<()> {
|
||||||
@@ -105,6 +106,6 @@ impl Emacs {
|
|||||||
#[cfg(not(unix))]
|
#[cfg(not(unix))]
|
||||||
command.arg(EMACS_UPGRADE);
|
command.arg(EMACS_UPGRADE);
|
||||||
|
|
||||||
command.check_run()
|
command.status_checked()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,13 +5,16 @@ use std::process::Command;
|
|||||||
use std::{env, path::Path};
|
use std::{env, path::Path};
|
||||||
use std::{fs, io::Write};
|
use std::{fs, io::Write};
|
||||||
|
|
||||||
use anyhow::Result;
|
use color_eyre::eyre::eyre;
|
||||||
|
use color_eyre::eyre::Context;
|
||||||
|
use color_eyre::eyre::Result;
|
||||||
use directories::BaseDirs;
|
use directories::BaseDirs;
|
||||||
use log::debug;
|
|
||||||
use tempfile::tempfile_in;
|
use tempfile::tempfile_in;
|
||||||
|
use tracing::debug;
|
||||||
|
|
||||||
|
use crate::command::{CommandExt, Utf8Output};
|
||||||
use crate::execution_context::ExecutionContext;
|
use crate::execution_context::ExecutionContext;
|
||||||
use crate::executor::{CommandExt, ExecutorOutput, RunType};
|
use crate::executor::{ExecutorOutput, RunType};
|
||||||
use crate::terminal::{print_separator, shell};
|
use crate::terminal::{print_separator, shell};
|
||||||
use crate::utils::{self, require_option, PathExt};
|
use crate::utils::{self, require_option, PathExt};
|
||||||
use crate::{
|
use crate::{
|
||||||
@@ -53,35 +56,21 @@ pub fn run_cargo_update(ctx: &ExecutionContext) -> Result<()> {
|
|||||||
ctx.run_type()
|
ctx.run_type()
|
||||||
.execute(cargo_update)
|
.execute(cargo_update)
|
||||||
.args(["install-update", "--git", "--all"])
|
.args(["install-update", "--git", "--all"])
|
||||||
.check_run()
|
.status_checked()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn run_flutter_upgrade(run_type: RunType) -> Result<()> {
|
pub fn run_flutter_upgrade(run_type: RunType) -> Result<()> {
|
||||||
let flutter = utils::require("flutter")?;
|
let flutter = utils::require("flutter")?;
|
||||||
|
|
||||||
print_separator("Flutter");
|
print_separator("Flutter");
|
||||||
run_type.execute(flutter).arg("upgrade").check_run()
|
run_type.execute(flutter).arg("upgrade").status_checked()
|
||||||
}
|
|
||||||
|
|
||||||
pub fn run_go(run_type: RunType) -> Result<()> {
|
|
||||||
let go = utils::require("go")?;
|
|
||||||
let go_output = run_type.execute(go).args(["env", "GOPATH"]).check_output()?;
|
|
||||||
let gopath = go_output.trim();
|
|
||||||
|
|
||||||
let go_global_update = utils::require("go-global-update")
|
|
||||||
.unwrap_or_else(|_| PathBuf::from(gopath).join("bin/go-global-update"))
|
|
||||||
.require()?;
|
|
||||||
|
|
||||||
print_separator("Go");
|
|
||||||
|
|
||||||
run_type.execute(go_global_update).check_run()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn run_gem(base_dirs: &BaseDirs, run_type: RunType) -> Result<()> {
|
pub fn run_gem(base_dirs: &BaseDirs, run_type: RunType) -> Result<()> {
|
||||||
let gem = utils::require("gem")?;
|
let gem = utils::require("gem")?;
|
||||||
base_dirs.home_dir().join(".gem").require()?;
|
base_dirs.home_dir().join(".gem").require()?;
|
||||||
|
|
||||||
print_separator("RubyGems");
|
print_separator("Gems");
|
||||||
|
|
||||||
let mut command = run_type.execute(gem);
|
let mut command = run_type.execute(gem);
|
||||||
command.arg("update");
|
command.arg("update");
|
||||||
@@ -91,14 +80,32 @@ pub fn run_gem(base_dirs: &BaseDirs, run_type: RunType) -> Result<()> {
|
|||||||
command.arg("--user-install");
|
command.arg("--user-install");
|
||||||
}
|
}
|
||||||
|
|
||||||
command.check_run()
|
command.status_checked()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn run_rubygems(base_dirs: &BaseDirs, run_type: RunType) -> Result<()> {
|
||||||
|
let gem = utils::require("gem")?;
|
||||||
|
base_dirs.home_dir().join(".gem").require()?;
|
||||||
|
|
||||||
|
print_separator("RubyGems");
|
||||||
|
|
||||||
|
let mut command = run_type.execute(gem);
|
||||||
|
command.arg("update --system");
|
||||||
|
|
||||||
|
if env::var_os("RBENV_SHELL").is_none() {
|
||||||
|
debug!("Detected rbenv. Avoiding --user-install");
|
||||||
|
command.arg("--user-install");
|
||||||
|
}
|
||||||
|
|
||||||
|
command.status_checked()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn run_haxelib_update(ctx: &ExecutionContext) -> Result<()> {
|
pub fn run_haxelib_update(ctx: &ExecutionContext) -> Result<()> {
|
||||||
let haxelib = utils::require("haxelib")?;
|
let haxelib = utils::require("haxelib")?;
|
||||||
|
|
||||||
let haxelib_dir =
|
let haxelib_dir =
|
||||||
PathBuf::from(std::str::from_utf8(&Command::new(&haxelib).arg("config").output()?.stdout)?.trim()).require()?;
|
PathBuf::from(std::str::from_utf8(&Command::new(&haxelib).arg("config").output_checked()?.stdout)?.trim())
|
||||||
|
.require()?;
|
||||||
|
|
||||||
let directory_writable = tempfile_in(&haxelib_dir).is_ok();
|
let directory_writable = tempfile_in(&haxelib_dir).is_ok();
|
||||||
debug!("{:?} writable: {}", haxelib_dir, directory_writable);
|
debug!("{:?} writable: {}", haxelib_dir, directory_writable);
|
||||||
@@ -115,7 +122,7 @@ pub fn run_haxelib_update(ctx: &ExecutionContext) -> Result<()> {
|
|||||||
c
|
c
|
||||||
};
|
};
|
||||||
|
|
||||||
command.arg("update").check_run()
|
command.arg("update").status_checked()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn run_sheldon(ctx: &ExecutionContext) -> Result<()> {
|
pub fn run_sheldon(ctx: &ExecutionContext) -> Result<()> {
|
||||||
@@ -123,7 +130,10 @@ pub fn run_sheldon(ctx: &ExecutionContext) -> Result<()> {
|
|||||||
|
|
||||||
print_separator("Sheldon");
|
print_separator("Sheldon");
|
||||||
|
|
||||||
ctx.run_type().execute(sheldon).args(["lock", "--update"]).check_run()
|
ctx.run_type()
|
||||||
|
.execute(sheldon)
|
||||||
|
.args(["lock", "--update"])
|
||||||
|
.status_checked()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn run_fossil(run_type: RunType) -> Result<()> {
|
pub fn run_fossil(run_type: RunType) -> Result<()> {
|
||||||
@@ -131,7 +141,7 @@ pub fn run_fossil(run_type: RunType) -> Result<()> {
|
|||||||
|
|
||||||
print_separator("Fossil");
|
print_separator("Fossil");
|
||||||
|
|
||||||
run_type.execute(fossil).args(["all", "sync"]).check_run()
|
run_type.execute(fossil).args(["all", "sync"]).status_checked()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn run_micro(run_type: RunType) -> Result<()> {
|
pub fn run_micro(run_type: RunType) -> Result<()> {
|
||||||
@@ -139,13 +149,17 @@ pub fn run_micro(run_type: RunType) -> Result<()> {
|
|||||||
|
|
||||||
print_separator("micro");
|
print_separator("micro");
|
||||||
|
|
||||||
let stdout = run_type.execute(micro).args(["-plugin", "update"]).string_output()?;
|
let stdout = run_type
|
||||||
|
.execute(micro)
|
||||||
|
.args(["-plugin", "update"])
|
||||||
|
.output_checked_utf8()?
|
||||||
|
.stdout;
|
||||||
std::io::stdout().write_all(stdout.as_bytes())?;
|
std::io::stdout().write_all(stdout.as_bytes())?;
|
||||||
|
|
||||||
if stdout.contains("Nothing to install / update") || stdout.contains("One or more plugins installed") {
|
if stdout.contains("Nothing to install / update") || stdout.contains("One or more plugins installed") {
|
||||||
Ok(())
|
Ok(())
|
||||||
} else {
|
} else {
|
||||||
Err(anyhow::anyhow!("micro output does not indicate success: {}", stdout))
|
Err(eyre!("micro output does not indicate success: {}", stdout))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -160,7 +174,10 @@ pub fn run_apm(run_type: RunType) -> Result<()> {
|
|||||||
|
|
||||||
print_separator("Atom Package Manager");
|
print_separator("Atom Package Manager");
|
||||||
|
|
||||||
run_type.execute(apm).args(["upgrade", "--confirm=false"]).check_run()
|
run_type
|
||||||
|
.execute(apm)
|
||||||
|
.args(["upgrade", "--confirm=false"])
|
||||||
|
.status_checked()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn run_rustup(base_dirs: &BaseDirs, run_type: RunType) -> Result<()> {
|
pub fn run_rustup(base_dirs: &BaseDirs, run_type: RunType) -> Result<()> {
|
||||||
@@ -169,10 +186,22 @@ pub fn run_rustup(base_dirs: &BaseDirs, run_type: RunType) -> Result<()> {
|
|||||||
print_separator("rustup");
|
print_separator("rustup");
|
||||||
|
|
||||||
if rustup.canonicalize()?.is_descendant_of(base_dirs.home_dir()) {
|
if rustup.canonicalize()?.is_descendant_of(base_dirs.home_dir()) {
|
||||||
run_type.execute(&rustup).args(["self", "update"]).check_run()?;
|
run_type.execute(&rustup).args(["self", "update"]).status_checked()?;
|
||||||
}
|
}
|
||||||
|
|
||||||
run_type.execute(&rustup).arg("update").check_run()
|
run_type.execute(&rustup).arg("update").status_checked()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn run_juliaup(base_dirs: &BaseDirs, run_type: RunType) -> Result<()> {
|
||||||
|
let juliaup = utils::require("juliaup")?;
|
||||||
|
|
||||||
|
print_separator("juliaup");
|
||||||
|
|
||||||
|
if juliaup.canonicalize()?.is_descendant_of(base_dirs.home_dir()) {
|
||||||
|
run_type.execute(&juliaup).args(["self", "update"]).status_checked()?;
|
||||||
|
}
|
||||||
|
|
||||||
|
run_type.execute(&juliaup).arg("update").status_checked()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn run_choosenim(ctx: &ExecutionContext) -> Result<()> {
|
pub fn run_choosenim(ctx: &ExecutionContext) -> Result<()> {
|
||||||
@@ -181,8 +210,8 @@ pub fn run_choosenim(ctx: &ExecutionContext) -> Result<()> {
|
|||||||
print_separator("choosenim");
|
print_separator("choosenim");
|
||||||
let run_type = ctx.run_type();
|
let run_type = ctx.run_type();
|
||||||
|
|
||||||
run_type.execute(&choosenim).args(["update", "self"]).check_run()?;
|
run_type.execute(&choosenim).args(["update", "self"]).status_checked()?;
|
||||||
run_type.execute(&choosenim).args(["update", "stable"]).check_run()
|
run_type.execute(&choosenim).args(["update", "stable"]).status_checked()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn run_krew_upgrade(run_type: RunType) -> Result<()> {
|
pub fn run_krew_upgrade(run_type: RunType) -> Result<()> {
|
||||||
@@ -190,18 +219,22 @@ pub fn run_krew_upgrade(run_type: RunType) -> Result<()> {
|
|||||||
|
|
||||||
print_separator("Krew");
|
print_separator("Krew");
|
||||||
|
|
||||||
run_type.execute(krew).args(["upgrade"]).check_run()
|
run_type.execute(krew).args(["upgrade"]).status_checked()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn run_gcloud_components_update(run_type: RunType) -> Result<()> {
|
pub fn run_gcloud_components_update(run_type: RunType) -> Result<()> {
|
||||||
let gcloud = utils::require("gcloud")?;
|
let gcloud = utils::require("gcloud")?;
|
||||||
|
|
||||||
print_separator("gcloud");
|
if gcloud.starts_with("/snap") {
|
||||||
|
Ok(())
|
||||||
|
} else {
|
||||||
|
print_separator("gcloud");
|
||||||
|
|
||||||
run_type
|
run_type
|
||||||
.execute(gcloud)
|
.execute(gcloud)
|
||||||
.args(["components", "update", "--quiet"])
|
.args(["components", "update", "--quiet"])
|
||||||
.check_run()
|
.status_checked()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn run_jetpack(run_type: RunType) -> Result<()> {
|
pub fn run_jetpack(run_type: RunType) -> Result<()> {
|
||||||
@@ -209,7 +242,7 @@ pub fn run_jetpack(run_type: RunType) -> Result<()> {
|
|||||||
|
|
||||||
print_separator("Jetpack");
|
print_separator("Jetpack");
|
||||||
|
|
||||||
run_type.execute(jetpack).args(["global", "update"]).check_run()
|
run_type.execute(jetpack).args(["global", "update"]).status_checked()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn run_rtcl(ctx: &ExecutionContext) -> Result<()> {
|
pub fn run_rtcl(ctx: &ExecutionContext) -> Result<()> {
|
||||||
@@ -217,7 +250,7 @@ pub fn run_rtcl(ctx: &ExecutionContext) -> Result<()> {
|
|||||||
|
|
||||||
print_separator("rtcl");
|
print_separator("rtcl");
|
||||||
|
|
||||||
ctx.run_type().execute(rupdate).check_run()
|
ctx.run_type().execute(rupdate).status_checked()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn run_opam_update(ctx: &ExecutionContext) -> Result<()> {
|
pub fn run_opam_update(ctx: &ExecutionContext) -> Result<()> {
|
||||||
@@ -225,11 +258,11 @@ pub fn run_opam_update(ctx: &ExecutionContext) -> Result<()> {
|
|||||||
|
|
||||||
print_separator("OCaml Package Manager");
|
print_separator("OCaml Package Manager");
|
||||||
|
|
||||||
ctx.run_type().execute(&opam).arg("update").check_run()?;
|
ctx.run_type().execute(&opam).arg("update").status_checked()?;
|
||||||
ctx.run_type().execute(&opam).arg("upgrade").check_run()?;
|
ctx.run_type().execute(&opam).arg("upgrade").status_checked()?;
|
||||||
|
|
||||||
if ctx.config().cleanup() {
|
if ctx.config().cleanup() {
|
||||||
ctx.run_type().execute(&opam).arg("clean").check_run()?;
|
ctx.run_type().execute(&opam).arg("clean").status_checked()?;
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
@@ -239,14 +272,17 @@ pub fn run_vcpkg_update(run_type: RunType) -> Result<()> {
|
|||||||
let vcpkg = utils::require("vcpkg")?;
|
let vcpkg = utils::require("vcpkg")?;
|
||||||
print_separator("vcpkg");
|
print_separator("vcpkg");
|
||||||
|
|
||||||
run_type.execute(vcpkg).args(["upgrade", "--no-dry-run"]).check_run()
|
run_type
|
||||||
|
.execute(vcpkg)
|
||||||
|
.args(["upgrade", "--no-dry-run"])
|
||||||
|
.status_checked()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn run_pipx_update(run_type: RunType) -> Result<()> {
|
pub fn run_pipx_update(run_type: RunType) -> Result<()> {
|
||||||
let pipx = utils::require("pipx")?;
|
let pipx = utils::require("pipx")?;
|
||||||
print_separator("pipx");
|
print_separator("pipx");
|
||||||
|
|
||||||
run_type.execute(pipx).arg("upgrade-all").check_run()
|
run_type.execute(pipx).arg("upgrade-all").status_checked()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn run_conda_update(ctx: &ExecutionContext) -> Result<()> {
|
pub fn run_conda_update(ctx: &ExecutionContext) -> Result<()> {
|
||||||
@@ -254,10 +290,9 @@ pub fn run_conda_update(ctx: &ExecutionContext) -> Result<()> {
|
|||||||
|
|
||||||
let output = Command::new("conda")
|
let output = Command::new("conda")
|
||||||
.args(["config", "--show", "auto_activate_base"])
|
.args(["config", "--show", "auto_activate_base"])
|
||||||
.output()?;
|
.output_checked_utf8()?;
|
||||||
let string_output = String::from_utf8(output.stdout)?;
|
debug!("Conda output: {}", output.stdout);
|
||||||
debug!("Conda output: {}", string_output);
|
if output.stdout.contains("False") {
|
||||||
if string_output.contains("False") {
|
|
||||||
return Err(SkipStep("auto_activate_base is set to False".to_string()).into());
|
return Err(SkipStep("auto_activate_base is set to False".to_string()).into());
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -266,14 +301,14 @@ pub fn run_conda_update(ctx: &ExecutionContext) -> Result<()> {
|
|||||||
ctx.run_type()
|
ctx.run_type()
|
||||||
.execute(conda)
|
.execute(conda)
|
||||||
.args(["update", "--all", "-y"])
|
.args(["update", "--all", "-y"])
|
||||||
.check_run()
|
.status_checked()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn run_pip3_update(run_type: RunType) -> Result<()> {
|
pub fn run_pip3_update(run_type: RunType) -> Result<()> {
|
||||||
let python3 = utils::require("python3")?;
|
let python3 = utils::require("python3")?;
|
||||||
Command::new(&python3)
|
Command::new(&python3)
|
||||||
.args(["-m", "pip"])
|
.args(["-m", "pip"])
|
||||||
.check_output()
|
.output_checked_utf8()
|
||||||
.map_err(|_| SkipStep("pip does not exists".to_string()))?;
|
.map_err(|_| SkipStep("pip does not exists".to_string()))?;
|
||||||
|
|
||||||
print_separator("pip3");
|
print_separator("pip3");
|
||||||
@@ -285,7 +320,7 @@ pub fn run_pip3_update(run_type: RunType) -> Result<()> {
|
|||||||
run_type
|
run_type
|
||||||
.execute(&python3)
|
.execute(&python3)
|
||||||
.args(["-m", "pip", "install", "--upgrade", "--user", "pip"])
|
.args(["-m", "pip", "install", "--upgrade", "--user", "pip"])
|
||||||
.check_run()
|
.status_checked()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn run_stack_update(run_type: RunType) -> Result<()> {
|
pub fn run_stack_update(run_type: RunType) -> Result<()> {
|
||||||
@@ -299,14 +334,14 @@ pub fn run_stack_update(run_type: RunType) -> Result<()> {
|
|||||||
let stack = utils::require("stack")?;
|
let stack = utils::require("stack")?;
|
||||||
print_separator("stack");
|
print_separator("stack");
|
||||||
|
|
||||||
run_type.execute(stack).arg("upgrade").check_run()
|
run_type.execute(stack).arg("upgrade").status_checked()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn run_ghcup_update(run_type: RunType) -> Result<()> {
|
pub fn run_ghcup_update(run_type: RunType) -> Result<()> {
|
||||||
let ghcup = utils::require("ghcup")?;
|
let ghcup = utils::require("ghcup")?;
|
||||||
print_separator("ghcup");
|
print_separator("ghcup");
|
||||||
|
|
||||||
run_type.execute(ghcup).arg("upgrade").check_run()
|
run_type.execute(ghcup).arg("upgrade").status_checked()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn run_tlmgr_update(ctx: &ExecutionContext) -> Result<()> {
|
pub fn run_tlmgr_update(ctx: &ExecutionContext) -> Result<()> {
|
||||||
@@ -322,13 +357,11 @@ pub fn run_tlmgr_update(ctx: &ExecutionContext) -> Result<()> {
|
|||||||
let kpsewhich = utils::require("kpsewhich")?;
|
let kpsewhich = utils::require("kpsewhich")?;
|
||||||
let tlmgr_directory = {
|
let tlmgr_directory = {
|
||||||
let mut d = PathBuf::from(
|
let mut d = PathBuf::from(
|
||||||
std::str::from_utf8(
|
&Command::new(kpsewhich)
|
||||||
&Command::new(kpsewhich)
|
.arg("-var-value=SELFAUTOPARENT")
|
||||||
.arg("-var-value=SELFAUTOPARENT")
|
.output_checked_utf8()?
|
||||||
.output()?
|
.stdout
|
||||||
.stdout,
|
.trim(),
|
||||||
)?
|
|
||||||
.trim(),
|
|
||||||
);
|
);
|
||||||
d.push("tlpkg");
|
d.push("tlpkg");
|
||||||
d
|
d
|
||||||
@@ -351,7 +384,7 @@ pub fn run_tlmgr_update(ctx: &ExecutionContext) -> Result<()> {
|
|||||||
};
|
};
|
||||||
command.args(["update", "--self", "--all"]);
|
command.args(["update", "--self", "--all"]);
|
||||||
|
|
||||||
command.check_run()
|
command.status_checked()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn run_chezmoi_update(base_dirs: &BaseDirs, run_type: RunType) -> Result<()> {
|
pub fn run_chezmoi_update(base_dirs: &BaseDirs, run_type: RunType) -> Result<()> {
|
||||||
@@ -360,7 +393,7 @@ pub fn run_chezmoi_update(base_dirs: &BaseDirs, run_type: RunType) -> Result<()>
|
|||||||
|
|
||||||
print_separator("chezmoi");
|
print_separator("chezmoi");
|
||||||
|
|
||||||
run_type.execute(chezmoi).arg("update").check_run()
|
run_type.execute(chezmoi).arg("update").status_checked()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn run_myrepos_update(base_dirs: &BaseDirs, run_type: RunType) -> Result<()> {
|
pub fn run_myrepos_update(base_dirs: &BaseDirs, run_type: RunType) -> Result<()> {
|
||||||
@@ -374,27 +407,27 @@ pub fn run_myrepos_update(base_dirs: &BaseDirs, run_type: RunType) -> Result<()>
|
|||||||
.arg("--directory")
|
.arg("--directory")
|
||||||
.arg(base_dirs.home_dir())
|
.arg(base_dirs.home_dir())
|
||||||
.arg("checkout")
|
.arg("checkout")
|
||||||
.check_run()?;
|
.status_checked()?;
|
||||||
run_type
|
run_type
|
||||||
.execute(&myrepos)
|
.execute(&myrepos)
|
||||||
.arg("--directory")
|
.arg("--directory")
|
||||||
.arg(base_dirs.home_dir())
|
.arg(base_dirs.home_dir())
|
||||||
.arg("update")
|
.arg("update")
|
||||||
.check_run()
|
.status_checked()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn run_custom_command(name: &str, command: &str, ctx: &ExecutionContext) -> Result<()> {
|
pub fn run_custom_command(name: &str, command: &str, ctx: &ExecutionContext) -> Result<()> {
|
||||||
print_separator(name);
|
print_separator(name);
|
||||||
ctx.run_type().execute(shell()).arg("-c").arg(command).check_run()
|
ctx.run_type().execute(shell()).arg("-c").arg(command).status_checked()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn run_composer_update(ctx: &ExecutionContext) -> Result<()> {
|
pub fn run_composer_update(ctx: &ExecutionContext) -> Result<()> {
|
||||||
let composer = utils::require("composer")?;
|
let composer = utils::require("composer")?;
|
||||||
let composer_home = Command::new(&composer)
|
let composer_home = Command::new(&composer)
|
||||||
.args(["global", "config", "--absolute", "--quiet", "home"])
|
.args(["global", "config", "--absolute", "--quiet", "home"])
|
||||||
.check_output()
|
.output_checked_utf8()
|
||||||
.map_err(|e| (SkipStep(format!("Error getting the composer directory: {}", e))))
|
.map_err(|e| (SkipStep(format!("Error getting the composer directory: {}", e))))
|
||||||
.map(|s| PathBuf::from(s.trim()))?
|
.map(|s| PathBuf::from(s.stdout.trim()))?
|
||||||
.require()?;
|
.require()?;
|
||||||
|
|
||||||
if !composer_home.is_descendant_of(ctx.base_dirs().home_dir()) {
|
if !composer_home.is_descendant_of(ctx.base_dirs().home_dir()) {
|
||||||
@@ -421,26 +454,22 @@ pub fn run_composer_update(ctx: &ExecutionContext) -> Result<()> {
|
|||||||
.execute(ctx.sudo().as_ref().unwrap())
|
.execute(ctx.sudo().as_ref().unwrap())
|
||||||
.arg(&composer)
|
.arg(&composer)
|
||||||
.arg("self-update")
|
.arg("self-update")
|
||||||
.check_run()?;
|
.status_checked()?;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
ctx.run_type().execute(&composer).arg("self-update").check_run()?;
|
ctx.run_type().execute(&composer).arg("self-update").status_checked()?;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let output = Command::new(&composer).args(["global", "update"]).output()?;
|
let output = ctx.run_type().execute(&composer).args(["global", "update"]).output()?;
|
||||||
let status = output.status;
|
if let ExecutorOutput::Wet(output) = output {
|
||||||
if !status.success() {
|
let output: Utf8Output = output.try_into()?;
|
||||||
return Err(TopgradeError::ProcessFailed(status).into());
|
print!("{}\n{}", output.stdout, output.stderr);
|
||||||
}
|
if output.stdout.contains("valet") || output.stderr.contains("valet") {
|
||||||
let stdout = String::from_utf8(output.stdout)?;
|
if let Some(valet) = utils::which("valet") {
|
||||||
let stderr = String::from_utf8(output.stderr)?;
|
ctx.run_type().execute(valet).arg("install").status_checked()?;
|
||||||
print!("{}\n{}", stdout, stderr);
|
}
|
||||||
|
|
||||||
if stdout.contains("valet") || stderr.contains("valet") {
|
|
||||||
if let Some(valet) = utils::which("valet") {
|
|
||||||
ctx.run_type().execute(valet).arg("install").check_run()?;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -450,18 +479,15 @@ pub fn run_composer_update(ctx: &ExecutionContext) -> Result<()> {
|
|||||||
pub fn run_dotnet_upgrade(ctx: &ExecutionContext) -> Result<()> {
|
pub fn run_dotnet_upgrade(ctx: &ExecutionContext) -> Result<()> {
|
||||||
let dotnet = utils::require("dotnet")?;
|
let dotnet = utils::require("dotnet")?;
|
||||||
|
|
||||||
let output = Command::new(dotnet).args(["tool", "list", "--global"]).output()?;
|
let output = Command::new(dotnet)
|
||||||
|
.args(["tool", "list", "--global"])
|
||||||
|
.output_checked_utf8()?;
|
||||||
|
|
||||||
if !output.status.success() {
|
if !output.stdout.starts_with("Package Id") {
|
||||||
return Err(SkipStep(format!("dotnet failed with exit code {:?}", output.status)).into());
|
|
||||||
}
|
|
||||||
|
|
||||||
let output = String::from_utf8(output.stdout)?;
|
|
||||||
if !output.starts_with("Package Id") {
|
|
||||||
return Err(SkipStep(String::from("dotnet did not output packages")).into());
|
return Err(SkipStep(String::from("dotnet did not output packages")).into());
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut packages = output.split('\n').skip(2).filter(|line| !line.is_empty()).peekable();
|
let mut packages = output.stdout.lines().skip(2).filter(|line| !line.is_empty()).peekable();
|
||||||
|
|
||||||
if packages.peek().is_none() {
|
if packages.peek().is_none() {
|
||||||
return Err(SkipStep(String::from("No dotnet global tools installed")).into());
|
return Err(SkipStep(String::from("No dotnet global tools installed")).into());
|
||||||
@@ -474,7 +500,8 @@ pub fn run_dotnet_upgrade(ctx: &ExecutionContext) -> Result<()> {
|
|||||||
ctx.run_type()
|
ctx.run_type()
|
||||||
.execute("dotnet")
|
.execute("dotnet")
|
||||||
.args(["tool", "update", package_name, "--global"])
|
.args(["tool", "update", package_name, "--global"])
|
||||||
.check_run()?;
|
.status_checked()
|
||||||
|
.with_context(|| format!("Failed to update .NET package {package_name}"))?;
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
@@ -485,26 +512,26 @@ pub fn run_raco_update(run_type: RunType) -> Result<()> {
|
|||||||
|
|
||||||
print_separator("Racket Package Manager");
|
print_separator("Racket Package Manager");
|
||||||
|
|
||||||
run_type.execute(raco).args(["pkg", "update", "--all"]).check_run()
|
run_type.execute(raco).args(["pkg", "update", "--all"]).status_checked()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn bin_update(ctx: &ExecutionContext) -> Result<()> {
|
pub fn bin_update(ctx: &ExecutionContext) -> Result<()> {
|
||||||
let bin = utils::require("bin")?;
|
let bin = utils::require("bin")?;
|
||||||
|
|
||||||
print_separator("Bin");
|
print_separator("Bin");
|
||||||
ctx.run_type().execute(bin).arg("update").check_run()
|
ctx.run_type().execute(bin).arg("update").status_checked()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn spicetify_upgrade(ctx: &ExecutionContext) -> Result<()> {
|
pub fn spicetify_upgrade(ctx: &ExecutionContext) -> Result<()> {
|
||||||
let spicetify = utils::require("spicetify")?;
|
let spicetify = utils::require("spicetify")?;
|
||||||
|
|
||||||
print_separator("Spicetify");
|
print_separator("Spicetify");
|
||||||
ctx.run_type().execute(spicetify).arg("upgrade").check_run()
|
ctx.run_type().execute(spicetify).arg("upgrade").status_checked()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn run_ghcli_extensions_upgrade(ctx: &ExecutionContext) -> Result<()> {
|
pub fn run_ghcli_extensions_upgrade(ctx: &ExecutionContext) -> Result<()> {
|
||||||
let gh = utils::require("gh")?;
|
let gh = utils::require("gh")?;
|
||||||
let result = Command::new(&gh).args(["extensions", "list"]).check_output();
|
let result = Command::new(&gh).args(["extensions", "list"]).output_checked_utf8();
|
||||||
if result.is_err() {
|
if result.is_err() {
|
||||||
debug!("GH result {:?}", result);
|
debug!("GH result {:?}", result);
|
||||||
return Err(SkipStep(String::from("GH failed")).into());
|
return Err(SkipStep(String::from("GH failed")).into());
|
||||||
@@ -514,7 +541,7 @@ pub fn run_ghcli_extensions_upgrade(ctx: &ExecutionContext) -> Result<()> {
|
|||||||
ctx.run_type()
|
ctx.run_type()
|
||||||
.execute(&gh)
|
.execute(&gh)
|
||||||
.args(["extension", "upgrade", "--all"])
|
.args(["extension", "upgrade", "--all"])
|
||||||
.check_run()
|
.status_checked()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn update_julia_packages(ctx: &ExecutionContext) -> Result<()> {
|
pub fn update_julia_packages(ctx: &ExecutionContext) -> Result<()> {
|
||||||
@@ -525,5 +552,5 @@ pub fn update_julia_packages(ctx: &ExecutionContext) -> Result<()> {
|
|||||||
ctx.run_type()
|
ctx.run_type()
|
||||||
.execute(julia)
|
.execute(julia)
|
||||||
.args(["-e", "using Pkg; Pkg.update()"])
|
.args(["-e", "using Pkg; Pkg.update()"])
|
||||||
.check_run()
|
.status_checked()
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,17 +3,18 @@ use std::io;
|
|||||||
use std::path::{Path, PathBuf};
|
use std::path::{Path, PathBuf};
|
||||||
use std::process::{Command, Output, Stdio};
|
use std::process::{Command, Output, Stdio};
|
||||||
|
|
||||||
use anyhow::{anyhow, Result};
|
use color_eyre::eyre::{eyre, Result};
|
||||||
use console::style;
|
use console::style;
|
||||||
use futures::stream::{iter, FuturesUnordered};
|
use futures::stream::{iter, FuturesUnordered};
|
||||||
use futures::StreamExt;
|
use futures::StreamExt;
|
||||||
use glob::{glob_with, MatchOptions};
|
use glob::{glob_with, MatchOptions};
|
||||||
use log::{debug, error};
|
|
||||||
use tokio::process::Command as AsyncCommand;
|
use tokio::process::Command as AsyncCommand;
|
||||||
use tokio::runtime;
|
use tokio::runtime;
|
||||||
|
use tracing::{debug, error};
|
||||||
|
|
||||||
|
use crate::command::CommandExt;
|
||||||
use crate::execution_context::ExecutionContext;
|
use crate::execution_context::ExecutionContext;
|
||||||
use crate::executor::{CommandExt, RunType};
|
use crate::executor::RunType;
|
||||||
use crate::terminal::print_separator;
|
use crate::terminal::print_separator;
|
||||||
use crate::utils::{which, PathExt};
|
use crate::utils::{which, PathExt};
|
||||||
use crate::{error::SkipStep, terminal::print_warning};
|
use crate::{error::SkipStep, terminal::print_warning};
|
||||||
@@ -33,10 +34,10 @@ pub struct Repositories<'a> {
|
|||||||
bad_patterns: Vec<String>,
|
bad_patterns: Vec<String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
fn check_output(output: Output) -> Result<()> {
|
fn output_checked_utf8(output: Output) -> Result<()> {
|
||||||
if !(output.status.success()) {
|
if !(output.status.success()) {
|
||||||
let stderr = String::from_utf8(output.stderr).unwrap();
|
let stderr = String::from_utf8(output.stderr).unwrap();
|
||||||
Err(anyhow!(stderr))
|
Err(eyre!(stderr))
|
||||||
} else {
|
} else {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
@@ -66,7 +67,7 @@ async fn pull_repository(repo: String, git: &Path, ctx: &ExecutionContext<'_>) -
|
|||||||
.stdin(Stdio::null())
|
.stdin(Stdio::null())
|
||||||
.output()
|
.output()
|
||||||
.await?;
|
.await?;
|
||||||
let result = check_output(pull_output).and_then(|_| check_output(submodule_output));
|
let result = output_checked_utf8(pull_output).and_then(|_| output_checked_utf8(submodule_output));
|
||||||
|
|
||||||
if let Err(message) = &result {
|
if let Err(message) = &result {
|
||||||
println!("{} pulling {}", style("Failed").red().bold(), &repo);
|
println!("{} pulling {}", style("Failed").red().bold(), &repo);
|
||||||
@@ -88,10 +89,7 @@ async fn pull_repository(repo: String, git: &Path, ctx: &ExecutionContext<'_>) -
|
|||||||
"--oneline",
|
"--oneline",
|
||||||
&format!("{}..{}", before, after),
|
&format!("{}..{}", before, after),
|
||||||
])
|
])
|
||||||
.spawn()
|
.status_checked()?;
|
||||||
.unwrap()
|
|
||||||
.wait()
|
|
||||||
.unwrap();
|
|
||||||
println!();
|
println!();
|
||||||
}
|
}
|
||||||
_ => {
|
_ => {
|
||||||
@@ -108,8 +106,8 @@ fn get_head_revision(git: &Path, repo: &str) -> Option<String> {
|
|||||||
.stdin(Stdio::null())
|
.stdin(Stdio::null())
|
||||||
.current_dir(repo)
|
.current_dir(repo)
|
||||||
.args(["rev-parse", "HEAD"])
|
.args(["rev-parse", "HEAD"])
|
||||||
.check_output()
|
.output_checked_utf8()
|
||||||
.map(|output| output.trim().to_string())
|
.map(|output| output.stdout.trim().to_string())
|
||||||
.map_err(|e| {
|
.map_err(|e| {
|
||||||
error!("Error getting revision for {}: {}", repo, e);
|
error!("Error getting revision for {}: {}", repo, e);
|
||||||
|
|
||||||
@@ -123,8 +121,8 @@ fn has_remotes(git: &Path, repo: &str) -> Option<bool> {
|
|||||||
.stdin(Stdio::null())
|
.stdin(Stdio::null())
|
||||||
.current_dir(repo)
|
.current_dir(repo)
|
||||||
.args(["remote", "show"])
|
.args(["remote", "show"])
|
||||||
.check_output()
|
.output_checked_utf8()
|
||||||
.map(|output| output.lines().count() > 0)
|
.map(|output| output.stdout.lines().count() > 0)
|
||||||
.map_err(|e| {
|
.map_err(|e| {
|
||||||
error!("Error getting remotes for {}: {}", repo, e);
|
error!("Error getting remotes for {}: {}", repo, e);
|
||||||
e
|
e
|
||||||
@@ -166,9 +164,9 @@ impl Git {
|
|||||||
.stdin(Stdio::null())
|
.stdin(Stdio::null())
|
||||||
.current_dir(path)
|
.current_dir(path)
|
||||||
.args(["rev-parse", "--show-toplevel"])
|
.args(["rev-parse", "--show-toplevel"])
|
||||||
.check_output()
|
.output_checked_utf8()
|
||||||
.ok()
|
.ok()
|
||||||
.map(|output| output.trim().to_string());
|
.map(|output| output.stdout.trim().to_string());
|
||||||
return output;
|
return output;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
45
src/steps/go.rs
Normal file
45
src/steps/go.rs
Normal file
@@ -0,0 +1,45 @@
|
|||||||
|
use std::path::PathBuf;
|
||||||
|
use std::process::Command;
|
||||||
|
|
||||||
|
use color_eyre::eyre::Result;
|
||||||
|
|
||||||
|
use crate::command::CommandExt;
|
||||||
|
use crate::executor::RunType;
|
||||||
|
use crate::terminal::print_separator;
|
||||||
|
use crate::utils;
|
||||||
|
use crate::utils::PathExt;
|
||||||
|
|
||||||
|
/// <https://github.com/Gelio/go-global-update>
|
||||||
|
pub fn run_go_global_update(run_type: RunType) -> Result<()> {
|
||||||
|
let go_global_update = require_go_bin("go-global-update")?;
|
||||||
|
|
||||||
|
print_separator("go-global-update");
|
||||||
|
|
||||||
|
run_type.execute(go_global_update).status_checked()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <https://github.com/nao1215/gup>
|
||||||
|
pub fn run_go_gup(run_type: RunType) -> Result<()> {
|
||||||
|
let gup = require_go_bin("gup")?;
|
||||||
|
|
||||||
|
print_separator("gup");
|
||||||
|
|
||||||
|
run_type.execute(gup).arg("update").status_checked()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Get the path of a Go binary.
|
||||||
|
fn require_go_bin(name: &str) -> Result<PathBuf> {
|
||||||
|
utils::require(name).or_else(|_| {
|
||||||
|
let go = utils::require("go")?;
|
||||||
|
// TODO: Does this work? `go help gopath` says that:
|
||||||
|
// > The GOPATH environment variable lists places to look for Go code.
|
||||||
|
// > On Unix, the value is a colon-separated string.
|
||||||
|
// > On Windows, the value is a semicolon-separated string.
|
||||||
|
// > On Plan 9, the value is a list.
|
||||||
|
// Should we also fallback to the env variable?
|
||||||
|
let gopath_output = Command::new(go).args(["env", "GOPATH"]).output_checked_utf8()?;
|
||||||
|
let gopath = gopath_output.stdout.trim();
|
||||||
|
|
||||||
|
PathBuf::from(gopath).join("bin").join(name).require()
|
||||||
|
})
|
||||||
|
}
|
||||||
@@ -1,10 +1,8 @@
|
|||||||
use crate::error::TopgradeError;
|
|
||||||
use crate::terminal::print_separator;
|
use crate::terminal::print_separator;
|
||||||
use crate::utils::require;
|
use crate::utils::require;
|
||||||
use anyhow::Result;
|
use color_eyre::eyre::Result;
|
||||||
|
|
||||||
use crate::execution_context::ExecutionContext;
|
use crate::execution_context::ExecutionContext;
|
||||||
use crate::executor::ExecutorOutput;
|
|
||||||
|
|
||||||
const UPGRADE_KAK: &str = include_str!("upgrade.kak");
|
const UPGRADE_KAK: &str = include_str!("upgrade.kak");
|
||||||
|
|
||||||
@@ -13,19 +11,13 @@ pub fn upgrade_kak_plug(ctx: &ExecutionContext) -> Result<()> {
|
|||||||
|
|
||||||
print_separator("Kakoune");
|
print_separator("Kakoune");
|
||||||
|
|
||||||
let mut command = ctx.run_type().execute(kak);
|
// TODO: Why supress output for this command?
|
||||||
command.args(["-ui", "dummy", "-e", UPGRADE_KAK]);
|
ctx.run_type()
|
||||||
|
.execute(kak)
|
||||||
|
.args(["-ui", "dummy", "-e", UPGRADE_KAK])
|
||||||
|
.output()?;
|
||||||
|
|
||||||
let output = command.output()?;
|
println!("Plugins upgraded");
|
||||||
|
|
||||||
if let ExecutorOutput::Wet(output) = output {
|
|
||||||
let status = output.status;
|
|
||||||
if !status.success() {
|
|
||||||
return Err(TopgradeError::ProcessFailed(status).into());
|
|
||||||
} else {
|
|
||||||
println!("Plugins upgraded")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ pub mod containers;
|
|||||||
pub mod emacs;
|
pub mod emacs;
|
||||||
pub mod generic;
|
pub mod generic;
|
||||||
pub mod git;
|
pub mod git;
|
||||||
|
pub mod go;
|
||||||
pub mod kakoune;
|
pub mod kakoune;
|
||||||
pub mod node;
|
pub mod node;
|
||||||
pub mod os;
|
pub mod os;
|
||||||
|
|||||||
@@ -1,19 +1,17 @@
|
|||||||
#![allow(unused_imports)]
|
|
||||||
|
|
||||||
use std::fmt::Display;
|
use std::fmt::Display;
|
||||||
#[cfg(unix)]
|
#[cfg(target_os = "linux")]
|
||||||
use std::os::unix::prelude::MetadataExt;
|
use std::os::unix::fs::MetadataExt;
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
use std::process::Command;
|
use std::process::Command;
|
||||||
|
|
||||||
use anyhow::Result;
|
use crate::utils::require_option;
|
||||||
use directories::BaseDirs;
|
use color_eyre::eyre::Result;
|
||||||
use log::debug;
|
#[cfg(target_os = "linux")]
|
||||||
#[cfg(unix)]
|
|
||||||
use nix::unistd::Uid;
|
use nix::unistd::Uid;
|
||||||
use semver::Version;
|
use semver::Version;
|
||||||
|
use tracing::debug;
|
||||||
|
|
||||||
use crate::executor::{CommandExt, RunType};
|
use crate::command::CommandExt;
|
||||||
use crate::terminal::print_separator;
|
use crate::terminal::print_separator;
|
||||||
use crate::utils::{require, PathExt};
|
use crate::utils::{require, PathExt};
|
||||||
use crate::{error::SkipStep, execution_context::ExecutionContext};
|
use crate::{error::SkipStep, execution_context::ExecutionContext};
|
||||||
@@ -24,13 +22,6 @@ enum NPMVariant {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl NPMVariant {
|
impl NPMVariant {
|
||||||
const fn long_name(&self) -> &str {
|
|
||||||
match self {
|
|
||||||
NPMVariant::Npm => "Node Package Manager",
|
|
||||||
NPMVariant::Pnpm => "PNPM",
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const fn short_name(&self) -> &str {
|
const fn short_name(&self) -> &str {
|
||||||
match self {
|
match self {
|
||||||
NPMVariant::Npm => "npm",
|
NPMVariant::Npm => "npm",
|
||||||
@@ -85,25 +76,29 @@ impl NPM {
|
|||||||
let args = ["root", self.global_location_arg()];
|
let args = ["root", self.global_location_arg()];
|
||||||
Command::new(&self.command)
|
Command::new(&self.command)
|
||||||
.args(args)
|
.args(args)
|
||||||
.check_output()
|
.output_checked_utf8()
|
||||||
.map(|s| PathBuf::from(s.trim()))
|
.map(|s| PathBuf::from(s.stdout.trim()))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn version(&self) -> Result<Version> {
|
fn version(&self) -> Result<Version> {
|
||||||
let version_str = Command::new(&self.command)
|
let version_str = Command::new(&self.command)
|
||||||
.args(["--version"])
|
.args(["--version"])
|
||||||
.check_output()
|
.output_checked_utf8()
|
||||||
.map(|s| s.trim().to_owned());
|
.map(|s| s.stdout.trim().to_owned());
|
||||||
Version::parse(&version_str?).map_err(|err| err.into())
|
Version::parse(&version_str?).map_err(|err| err.into())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn upgrade(&self, run_type: RunType, use_sudo: bool) -> Result<()> {
|
fn upgrade(&self, ctx: &ExecutionContext, use_sudo: bool) -> Result<()> {
|
||||||
print_separator(self.variant.long_name());
|
|
||||||
let args = ["update", self.global_location_arg()];
|
let args = ["update", self.global_location_arg()];
|
||||||
if use_sudo {
|
if use_sudo {
|
||||||
run_type.execute("sudo").args(args).check_run()?;
|
let sudo = require_option(ctx.sudo().clone(), String::from("sudo is not installed"))?;
|
||||||
|
ctx.run_type()
|
||||||
|
.execute(sudo)
|
||||||
|
.arg(&self.command)
|
||||||
|
.args(args)
|
||||||
|
.status_checked()?;
|
||||||
} else {
|
} else {
|
||||||
run_type.execute(&self.command).args(args).check_run()?;
|
ctx.run_type().execute(&self.command).args(args).status_checked()?;
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
@@ -142,9 +137,9 @@ impl Yarn {
|
|||||||
//
|
//
|
||||||
// As “yarn dlx” don't need to “upgrade”, we
|
// As “yarn dlx” don't need to “upgrade”, we
|
||||||
// ignore the whole task if Yarn is 2.x or above.
|
// ignore the whole task if Yarn is 2.x or above.
|
||||||
let version = Command::new(&self.command).args(["--version"]).check_output();
|
let version = Command::new(&self.command).args(["--version"]).output_checked_utf8();
|
||||||
|
|
||||||
matches!(version, Ok(ver) if ver.starts_with('1') || ver.starts_with('0'))
|
matches!(version, Ok(ver) if ver.stdout.starts_with('1') || ver.stdout.starts_with('0'))
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(target_os = "linux")]
|
#[cfg(target_os = "linux")]
|
||||||
@@ -152,22 +147,22 @@ impl Yarn {
|
|||||||
let args = ["global", "dir"];
|
let args = ["global", "dir"];
|
||||||
Command::new(&self.command)
|
Command::new(&self.command)
|
||||||
.args(args)
|
.args(args)
|
||||||
.check_output()
|
.output_checked_utf8()
|
||||||
.map(|s| PathBuf::from(s.trim()))
|
.map(|s| PathBuf::from(s.stdout.trim()))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn upgrade(&self, run_type: RunType, use_sudo: bool) -> Result<()> {
|
fn upgrade(&self, ctx: &ExecutionContext, use_sudo: bool) -> Result<()> {
|
||||||
print_separator("Yarn Package Manager");
|
|
||||||
let args = ["global", "upgrade"];
|
let args = ["global", "upgrade"];
|
||||||
|
|
||||||
if use_sudo {
|
if use_sudo {
|
||||||
run_type
|
let sudo = require_option(ctx.sudo().clone(), String::from("sudo is not installed"))?;
|
||||||
.execute("sudo")
|
ctx.run_type()
|
||||||
|
.execute(sudo)
|
||||||
.arg(self.yarn.as_ref().unwrap_or(&self.command))
|
.arg(self.yarn.as_ref().unwrap_or(&self.command))
|
||||||
.args(args)
|
.args(args)
|
||||||
.check_run()?;
|
.status_checked()?;
|
||||||
} else {
|
} else {
|
||||||
run_type.execute(&self.command).args(args).check_run()?;
|
ctx.run_type().execute(&self.command).args(args).status_checked()?;
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
@@ -218,28 +213,32 @@ fn should_use_sudo_yarn(yarn: &Yarn, ctx: &ExecutionContext) -> Result<bool> {
|
|||||||
pub fn run_npm_upgrade(ctx: &ExecutionContext) -> Result<()> {
|
pub fn run_npm_upgrade(ctx: &ExecutionContext) -> Result<()> {
|
||||||
let npm = require("npm").map(|b| NPM::new(b, NPMVariant::Npm))?;
|
let npm = require("npm").map(|b| NPM::new(b, NPMVariant::Npm))?;
|
||||||
|
|
||||||
|
print_separator("Node Package Manager");
|
||||||
|
|
||||||
#[cfg(target_os = "linux")]
|
#[cfg(target_os = "linux")]
|
||||||
{
|
{
|
||||||
npm.upgrade(ctx.run_type(), should_use_sudo(&npm, ctx)?)
|
npm.upgrade(ctx, should_use_sudo(&npm, ctx)?)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(not(target_os = "linux"))]
|
#[cfg(not(target_os = "linux"))]
|
||||||
{
|
{
|
||||||
npm.upgrade(ctx.run_type(), false)
|
npm.upgrade(ctx, false)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn run_pnpm_upgrade(ctx: &ExecutionContext) -> Result<()> {
|
pub fn run_pnpm_upgrade(ctx: &ExecutionContext) -> Result<()> {
|
||||||
let pnpm = require("pnpm").map(|b| NPM::new(b, NPMVariant::Pnpm))?;
|
let pnpm = require("pnpm").map(|b| NPM::new(b, NPMVariant::Pnpm))?;
|
||||||
|
|
||||||
|
print_separator("Node Package Manager");
|
||||||
|
|
||||||
#[cfg(target_os = "linux")]
|
#[cfg(target_os = "linux")]
|
||||||
{
|
{
|
||||||
pnpm.upgrade(ctx.run_type(), should_use_sudo(&pnpm, ctx)?)
|
pnpm.upgrade(ctx, should_use_sudo(&pnpm, ctx)?)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(not(target_os = "linux"))]
|
#[cfg(not(target_os = "linux"))]
|
||||||
{
|
{
|
||||||
pnpm.upgrade(ctx.run_type(), false)
|
pnpm.upgrade(ctx, false)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -251,14 +250,16 @@ pub fn run_yarn_upgrade(ctx: &ExecutionContext) -> Result<()> {
|
|||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
print_separator("Yarn Package Manager");
|
||||||
|
|
||||||
#[cfg(target_os = "linux")]
|
#[cfg(target_os = "linux")]
|
||||||
{
|
{
|
||||||
yarn.upgrade(ctx.run_type(), should_use_sudo_yarn(&yarn, ctx)?)
|
yarn.upgrade(ctx, should_use_sudo_yarn(&yarn, ctx)?)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(not(target_os = "linux"))]
|
#[cfg(not(target_os = "linux"))]
|
||||||
{
|
{
|
||||||
yarn.upgrade(ctx.run_type(), false)
|
yarn.upgrade(ctx, false)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -272,5 +273,5 @@ pub fn deno_upgrade(ctx: &ExecutionContext) -> Result<()> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
print_separator("Deno");
|
print_separator("Deno");
|
||||||
ctx.run_type().execute(&deno).arg("upgrade").check_run()
|
ctx.run_type().execute(&deno).arg("upgrade").status_checked()
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,8 +1,10 @@
|
|||||||
|
use crate::command::CommandExt;
|
||||||
use crate::execution_context::ExecutionContext;
|
use crate::execution_context::ExecutionContext;
|
||||||
use crate::terminal::print_separator;
|
use crate::terminal::print_separator;
|
||||||
use crate::utils::require;
|
use crate::utils::require;
|
||||||
|
use crate::utils::which;
|
||||||
use crate::Step;
|
use crate::Step;
|
||||||
use anyhow::Result;
|
use color_eyre::eyre::Result;
|
||||||
|
|
||||||
pub fn upgrade_packages(ctx: &ExecutionContext) -> Result<()> {
|
pub fn upgrade_packages(ctx: &ExecutionContext) -> Result<()> {
|
||||||
//let pkg = require("pkg")?;
|
//let pkg = require("pkg")?;
|
||||||
@@ -10,7 +12,7 @@ pub fn upgrade_packages(ctx: &ExecutionContext) -> Result<()> {
|
|||||||
|
|
||||||
print_separator("Termux Packages");
|
print_separator("Termux Packages");
|
||||||
|
|
||||||
let is_nala = pkg.end_with("nala");
|
let is_nala = pkg.ends_with("nala");
|
||||||
|
|
||||||
let mut command = ctx.run_type().execute(&pkg);
|
let mut command = ctx.run_type().execute(&pkg);
|
||||||
command.arg("upgrade");
|
command.arg("upgrade");
|
||||||
@@ -18,20 +20,18 @@ pub fn upgrade_packages(ctx: &ExecutionContext) -> Result<()> {
|
|||||||
if ctx.config().yes(Step::System) {
|
if ctx.config().yes(Step::System) {
|
||||||
command.arg("-y");
|
command.arg("-y");
|
||||||
}
|
}
|
||||||
command.check_run()?;
|
command.status_checked()?;
|
||||||
|
|
||||||
if !is_nala {
|
if !is_nala && ctx.config().cleanup() {
|
||||||
if ctx.config().cleanup() {
|
ctx.run_type().execute(&pkg).arg("clean").status_checked()?;
|
||||||
ctx.run_type().execute(&pkg).arg("clean").check_run()?;
|
|
||||||
|
|
||||||
let apt = require("apt")?;
|
let apt = require("apt")?;
|
||||||
let mut command = ctx.run_type().execute(&apt);
|
let mut command = ctx.run_type().execute(&apt);
|
||||||
command.arg("autoremove");
|
command.arg("autoremove");
|
||||||
if ctx.config().yes(Step::System) {
|
if ctx.config().yes(Step::System) {
|
||||||
command.arg("-y");
|
command.arg("-y");
|
||||||
}
|
|
||||||
command.check_run()?;
|
|
||||||
}
|
}
|
||||||
|
command.status_checked()?;
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
|
|||||||
@@ -1,13 +1,15 @@
|
|||||||
use std::env::var_os;
|
use std::env::var_os;
|
||||||
use std::ffi::OsString;
|
use std::ffi::OsString;
|
||||||
use std::path::{Path, PathBuf};
|
use std::path::{Path, PathBuf};
|
||||||
use std::process::Command;
|
|
||||||
|
|
||||||
use anyhow::Result;
|
use color_eyre::eyre;
|
||||||
|
use color_eyre::eyre::Result;
|
||||||
use walkdir::WalkDir;
|
use walkdir::WalkDir;
|
||||||
|
|
||||||
|
use crate::command::CommandExt;
|
||||||
use crate::error::TopgradeError;
|
use crate::error::TopgradeError;
|
||||||
use crate::execution_context::ExecutionContext;
|
use crate::execution_context::ExecutionContext;
|
||||||
|
use crate::sudo::Sudo;
|
||||||
use crate::utils::which;
|
use crate::utils::which;
|
||||||
use crate::{config, Step};
|
use crate::{config, Step};
|
||||||
|
|
||||||
@@ -29,11 +31,10 @@ pub struct YayParu {
|
|||||||
impl ArchPackageManager for YayParu {
|
impl ArchPackageManager for YayParu {
|
||||||
fn upgrade(&self, ctx: &ExecutionContext) -> Result<()> {
|
fn upgrade(&self, ctx: &ExecutionContext) -> Result<()> {
|
||||||
if ctx.config().show_arch_news() {
|
if ctx.config().show_arch_news() {
|
||||||
Command::new(&self.executable)
|
ctx.run_type()
|
||||||
|
.execute(&self.executable)
|
||||||
.arg("-Pw")
|
.arg("-Pw")
|
||||||
.spawn()
|
.status_checked_with_codes(&[1, 0])?;
|
||||||
.and_then(|mut p| p.wait())
|
|
||||||
.ok();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut command = ctx.run_type().execute(&self.executable);
|
let mut command = ctx.run_type().execute(&self.executable);
|
||||||
@@ -48,7 +49,7 @@ impl ArchPackageManager for YayParu {
|
|||||||
if ctx.config().yes(Step::System) {
|
if ctx.config().yes(Step::System) {
|
||||||
command.arg("--noconfirm");
|
command.arg("--noconfirm");
|
||||||
}
|
}
|
||||||
command.check_run()?;
|
command.status_checked()?;
|
||||||
|
|
||||||
if ctx.config().cleanup() {
|
if ctx.config().cleanup() {
|
||||||
let mut command = ctx.run_type().execute(&self.executable);
|
let mut command = ctx.run_type().execute(&self.executable);
|
||||||
@@ -56,7 +57,7 @@ impl ArchPackageManager for YayParu {
|
|||||||
if ctx.config().yes(Step::System) {
|
if ctx.config().yes(Step::System) {
|
||||||
command.arg("--noconfirm");
|
command.arg("--noconfirm");
|
||||||
}
|
}
|
||||||
command.check_run()?;
|
command.status_checked()?;
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
@@ -72,6 +73,27 @@ impl YayParu {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub struct GarudaUpdate {
|
||||||
|
executable: PathBuf,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ArchPackageManager for GarudaUpdate {
|
||||||
|
fn upgrade(&self, ctx: &ExecutionContext) -> Result<()> {
|
||||||
|
let mut command = ctx.run_type().execute(&self.executable);
|
||||||
|
command.env("PATH", get_execution_path());
|
||||||
|
command.status_checked()?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl GarudaUpdate {
|
||||||
|
fn get() -> Option<Self> {
|
||||||
|
Some(Self {
|
||||||
|
executable: which("garuda-update")?,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub struct Trizen {
|
pub struct Trizen {
|
||||||
executable: PathBuf,
|
executable: PathBuf,
|
||||||
}
|
}
|
||||||
@@ -88,7 +110,7 @@ impl ArchPackageManager for Trizen {
|
|||||||
if ctx.config().yes(Step::System) {
|
if ctx.config().yes(Step::System) {
|
||||||
command.arg("--noconfirm");
|
command.arg("--noconfirm");
|
||||||
}
|
}
|
||||||
command.check_run()?;
|
command.status_checked()?;
|
||||||
|
|
||||||
if ctx.config().cleanup() {
|
if ctx.config().cleanup() {
|
||||||
let mut command = ctx.run_type().execute(&self.executable);
|
let mut command = ctx.run_type().execute(&self.executable);
|
||||||
@@ -96,7 +118,7 @@ impl ArchPackageManager for Trizen {
|
|||||||
if ctx.config().yes(Step::System) {
|
if ctx.config().yes(Step::System) {
|
||||||
command.arg("--noconfirm");
|
command.arg("--noconfirm");
|
||||||
}
|
}
|
||||||
command.check_run()?;
|
command.status_checked()?;
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
@@ -112,7 +134,7 @@ impl Trizen {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub struct Pacman {
|
pub struct Pacman {
|
||||||
sudo: PathBuf,
|
sudo: Sudo,
|
||||||
executable: PathBuf,
|
executable: PathBuf,
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -126,7 +148,7 @@ impl ArchPackageManager for Pacman {
|
|||||||
if ctx.config().yes(Step::System) {
|
if ctx.config().yes(Step::System) {
|
||||||
command.arg("--noconfirm");
|
command.arg("--noconfirm");
|
||||||
}
|
}
|
||||||
command.check_run()?;
|
command.status_checked()?;
|
||||||
|
|
||||||
if ctx.config().cleanup() {
|
if ctx.config().cleanup() {
|
||||||
let mut command = ctx.run_type().execute(&self.sudo);
|
let mut command = ctx.run_type().execute(&self.sudo);
|
||||||
@@ -134,7 +156,7 @@ impl ArchPackageManager for Pacman {
|
|||||||
if ctx.config().yes(Step::System) {
|
if ctx.config().yes(Step::System) {
|
||||||
command.arg("--noconfirm");
|
command.arg("--noconfirm");
|
||||||
}
|
}
|
||||||
command.check_run()?;
|
command.status_checked()?;
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
@@ -175,7 +197,7 @@ impl ArchPackageManager for Pikaur {
|
|||||||
command.arg("--noconfirm");
|
command.arg("--noconfirm");
|
||||||
}
|
}
|
||||||
|
|
||||||
command.check_run()?;
|
command.status_checked()?;
|
||||||
|
|
||||||
if ctx.config().cleanup() {
|
if ctx.config().cleanup() {
|
||||||
let mut command = ctx.run_type().execute(&self.executable);
|
let mut command = ctx.run_type().execute(&self.executable);
|
||||||
@@ -183,7 +205,7 @@ impl ArchPackageManager for Pikaur {
|
|||||||
if ctx.config().yes(Step::System) {
|
if ctx.config().yes(Step::System) {
|
||||||
command.arg("--noconfirm");
|
command.arg("--noconfirm");
|
||||||
}
|
}
|
||||||
command.check_run()?;
|
command.status_checked()?;
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
@@ -214,7 +236,7 @@ impl ArchPackageManager for Pamac {
|
|||||||
command.arg("--no-confirm");
|
command.arg("--no-confirm");
|
||||||
}
|
}
|
||||||
|
|
||||||
command.check_run()?;
|
command.status_checked()?;
|
||||||
|
|
||||||
if ctx.config().cleanup() {
|
if ctx.config().cleanup() {
|
||||||
let mut command = ctx.run_type().execute(&self.executable);
|
let mut command = ctx.run_type().execute(&self.executable);
|
||||||
@@ -222,7 +244,7 @@ impl ArchPackageManager for Pamac {
|
|||||||
if ctx.config().yes(Step::System) {
|
if ctx.config().yes(Step::System) {
|
||||||
command.arg("--no-confirm");
|
command.arg("--no-confirm");
|
||||||
}
|
}
|
||||||
command.check_run()?;
|
command.status_checked()?;
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
@@ -231,7 +253,7 @@ impl ArchPackageManager for Pamac {
|
|||||||
|
|
||||||
pub struct Aura {
|
pub struct Aura {
|
||||||
executable: PathBuf,
|
executable: PathBuf,
|
||||||
sudo: PathBuf,
|
sudo: Sudo,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Aura {
|
impl Aura {
|
||||||
@@ -257,7 +279,7 @@ impl ArchPackageManager for Aura {
|
|||||||
aur_update.arg("--noconfirm");
|
aur_update.arg("--noconfirm");
|
||||||
}
|
}
|
||||||
|
|
||||||
aur_update.check_run()?;
|
aur_update.status_checked()?;
|
||||||
} else {
|
} else {
|
||||||
println!("Aura requires sudo installed to work with AUR packages")
|
println!("Aura requires sudo installed to work with AUR packages")
|
||||||
}
|
}
|
||||||
@@ -270,7 +292,7 @@ impl ArchPackageManager for Aura {
|
|||||||
if ctx.config().yes(Step::System) {
|
if ctx.config().yes(Step::System) {
|
||||||
pacman_update.arg("--noconfirm");
|
pacman_update.arg("--noconfirm");
|
||||||
}
|
}
|
||||||
pacman_update.check_run()?;
|
pacman_update.status_checked()?;
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
@@ -284,14 +306,16 @@ pub fn get_arch_package_manager(ctx: &ExecutionContext) -> Option<Box<dyn ArchPa
|
|||||||
let pacman = which("powerpill").unwrap_or_else(|| PathBuf::from("pacman"));
|
let pacman = which("powerpill").unwrap_or_else(|| PathBuf::from("pacman"));
|
||||||
|
|
||||||
match ctx.config().arch_package_manager() {
|
match ctx.config().arch_package_manager() {
|
||||||
config::ArchPackageManager::Autodetect => YayParu::get("paru", &pacman)
|
config::ArchPackageManager::Autodetect => GarudaUpdate::get()
|
||||||
.map(box_package_manager)
|
.map(box_package_manager)
|
||||||
|
.or_else(|| YayParu::get("paru", &pacman).map(box_package_manager))
|
||||||
.or_else(|| YayParu::get("yay", &pacman).map(box_package_manager))
|
.or_else(|| YayParu::get("yay", &pacman).map(box_package_manager))
|
||||||
.or_else(|| Trizen::get().map(box_package_manager))
|
.or_else(|| Trizen::get().map(box_package_manager))
|
||||||
.or_else(|| Pikaur::get().map(box_package_manager))
|
.or_else(|| Pikaur::get().map(box_package_manager))
|
||||||
.or_else(|| Pamac::get().map(box_package_manager))
|
.or_else(|| Pamac::get().map(box_package_manager))
|
||||||
.or_else(|| Pacman::get(ctx).map(box_package_manager))
|
.or_else(|| Pacman::get(ctx).map(box_package_manager))
|
||||||
.or_else(|| Aura::get(ctx).map(box_package_manager)),
|
.or_else(|| Aura::get(ctx).map(box_package_manager)),
|
||||||
|
config::ArchPackageManager::GarudaUpdate => GarudaUpdate::get().map(box_package_manager),
|
||||||
config::ArchPackageManager::Trizen => Trizen::get().map(box_package_manager),
|
config::ArchPackageManager::Trizen => Trizen::get().map(box_package_manager),
|
||||||
config::ArchPackageManager::Paru => YayParu::get("paru", &pacman).map(box_package_manager),
|
config::ArchPackageManager::Paru => YayParu::get("paru", &pacman).map(box_package_manager),
|
||||||
config::ArchPackageManager::Yay => YayParu::get("yay", &pacman).map(box_package_manager),
|
config::ArchPackageManager::Yay => YayParu::get("yay", &pacman).map(box_package_manager),
|
||||||
@@ -304,7 +328,7 @@ pub fn get_arch_package_manager(ctx: &ExecutionContext) -> Option<Box<dyn ArchPa
|
|||||||
|
|
||||||
pub fn upgrade_arch_linux(ctx: &ExecutionContext) -> Result<()> {
|
pub fn upgrade_arch_linux(ctx: &ExecutionContext) -> Result<()> {
|
||||||
let package_manager =
|
let package_manager =
|
||||||
get_arch_package_manager(ctx).ok_or_else(|| anyhow::Error::from(TopgradeError::FailedGettingPackageManager))?;
|
get_arch_package_manager(ctx).ok_or_else(|| eyre::Report::from(TopgradeError::FailedGettingPackageManager))?;
|
||||||
package_manager.upgrade(ctx)
|
package_manager.upgrade(ctx)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,26 +1,26 @@
|
|||||||
|
use crate::command::CommandExt;
|
||||||
use crate::executor::RunType;
|
use crate::executor::RunType;
|
||||||
|
use crate::sudo::Sudo;
|
||||||
use crate::terminal::print_separator;
|
use crate::terminal::print_separator;
|
||||||
use crate::utils::require_option;
|
use crate::utils::require_option;
|
||||||
use anyhow::Result;
|
use color_eyre::eyre::Result;
|
||||||
use std::path::PathBuf;
|
|
||||||
use std::process::Command;
|
use std::process::Command;
|
||||||
|
|
||||||
pub fn upgrade_packages(sudo: Option<&PathBuf>, run_type: RunType) -> Result<()> {
|
pub fn upgrade_packages(sudo: Option<&Sudo>, run_type: RunType) -> Result<()> {
|
||||||
let sudo = require_option(sudo, String::from("No sudo detected"))?;
|
let sudo = require_option(sudo, String::from("No sudo detected"))?;
|
||||||
print_separator("DrgaonFly BSD Packages");
|
print_separator("DragonFly BSD Packages");
|
||||||
run_type
|
run_type
|
||||||
.execute(sudo)
|
.execute(sudo)
|
||||||
.args(&["/usr/local/sbin/pkg", "upgrade"])
|
.args(["/usr/local/sbin/pkg", "upgrade"])
|
||||||
.check_run()
|
.status_checked()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn audit_packages(sudo: &Option<PathBuf>) -> Result<()> {
|
pub fn audit_packages(sudo: Option<&Sudo>) -> Result<()> {
|
||||||
if let Some(sudo) = sudo {
|
if let Some(sudo) = sudo {
|
||||||
println!();
|
println!();
|
||||||
Command::new(sudo)
|
Command::new(sudo)
|
||||||
.args(&["/usr/local/sbin/pkg", "audit", "-Fr"])
|
.args(["/usr/local/sbin/pkg", "audit", "-Fr"])
|
||||||
.spawn()?
|
.status_checked()?;
|
||||||
.wait()?;
|
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,32 +1,41 @@
|
|||||||
|
use crate::command::CommandExt;
|
||||||
|
use crate::execution_context::ExecutionContext;
|
||||||
use crate::executor::RunType;
|
use crate::executor::RunType;
|
||||||
|
use crate::sudo::Sudo;
|
||||||
use crate::terminal::print_separator;
|
use crate::terminal::print_separator;
|
||||||
use crate::utils::require_option;
|
use crate::utils::require_option;
|
||||||
use anyhow::Result;
|
use crate::Step;
|
||||||
use std::path::PathBuf;
|
use color_eyre::eyre::Result;
|
||||||
use std::process::Command;
|
use std::process::Command;
|
||||||
|
|
||||||
pub fn upgrade_freebsd(sudo: Option<&PathBuf>, run_type: RunType) -> Result<()> {
|
pub fn upgrade_freebsd(sudo: Option<&Sudo>, run_type: RunType) -> Result<()> {
|
||||||
let sudo = require_option(sudo, String::from("No sudo detected"))?;
|
let sudo = require_option(sudo, String::from("No sudo detected"))?;
|
||||||
print_separator("FreeBSD Update");
|
print_separator("FreeBSD Update");
|
||||||
run_type
|
run_type
|
||||||
.execute(sudo)
|
.execute(sudo)
|
||||||
.args(&["/usr/sbin/freebsd-update", "fetch", "install"])
|
.args(["/usr/sbin/freebsd-update", "fetch", "install"])
|
||||||
.check_run()
|
.status_checked()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn upgrade_packages(sudo: Option<&PathBuf>, run_type: RunType) -> Result<()> {
|
pub fn upgrade_packages(ctx: &ExecutionContext, sudo: Option<&Sudo>, run_type: RunType) -> Result<()> {
|
||||||
let sudo = require_option(sudo, String::from("No sudo detected"))?;
|
let sudo = require_option(sudo, String::from("No sudo detected"))?;
|
||||||
print_separator("FreeBSD Packages");
|
print_separator("FreeBSD Packages");
|
||||||
run_type.execute(sudo).args(&["/usr/sbin/pkg", "upgrade"]).check_run()
|
|
||||||
|
let mut command = run_type.execute(sudo);
|
||||||
|
|
||||||
|
command.args(["/usr/sbin/pkg", "upgrade"]);
|
||||||
|
if ctx.config().yes(Step::System) {
|
||||||
|
command.arg("-y");
|
||||||
|
}
|
||||||
|
command.status_checked()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn audit_packages(sudo: &Option<PathBuf>) -> Result<()> {
|
pub fn audit_packages(sudo: Option<&Sudo>) -> Result<()> {
|
||||||
if let Some(sudo) = sudo {
|
if let Some(sudo) = sudo {
|
||||||
println!();
|
println!();
|
||||||
Command::new(sudo)
|
Command::new(sudo)
|
||||||
.args(&["/usr/sbin/pkg", "audit", "-Fr"])
|
.args(["/usr/sbin/pkg", "audit", "-Fr"])
|
||||||
.spawn()?
|
.status_checked()?;
|
||||||
.wait()?;
|
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,14 +1,16 @@
|
|||||||
use std::path::{Path, PathBuf};
|
use std::path::{Path, PathBuf};
|
||||||
use std::process::Command;
|
use std::process::Command;
|
||||||
|
|
||||||
use anyhow::Result;
|
use color_eyre::eyre::Result;
|
||||||
use ini::Ini;
|
use ini::Ini;
|
||||||
use log::{debug, warn};
|
use tracing::{debug, warn};
|
||||||
|
|
||||||
|
use crate::command::CommandExt;
|
||||||
use crate::error::{SkipStep, TopgradeError};
|
use crate::error::{SkipStep, TopgradeError};
|
||||||
use crate::execution_context::ExecutionContext;
|
use crate::execution_context::ExecutionContext;
|
||||||
use crate::executor::{CommandExt, RunType};
|
use crate::executor::RunType;
|
||||||
use crate::steps::os::archlinux;
|
use crate::steps::os::archlinux;
|
||||||
|
use crate::sudo::Sudo;
|
||||||
use crate::terminal::{print_separator, print_warning};
|
use crate::terminal::{print_separator, print_warning};
|
||||||
use crate::utils::{require, require_option, which, PathExt};
|
use crate::utils::{require, require_option, which, PathExt};
|
||||||
use crate::Step;
|
use crate::Step;
|
||||||
@@ -127,11 +129,10 @@ fn update_bedrock(ctx: &ExecutionContext) -> Result<()> {
|
|||||||
|
|
||||||
ctx.run_type().execute(sudo).args(["brl", "update"]);
|
ctx.run_type().execute(sudo).args(["brl", "update"]);
|
||||||
|
|
||||||
let output = Command::new("brl").arg("list").output()?;
|
let output = Command::new("brl").arg("list").output_checked_utf8()?;
|
||||||
debug!("brl list: {:?} {:?}", output.stdout, output.stderr);
|
debug!("brl list: {:?} {:?}", output.stdout, output.stderr);
|
||||||
|
|
||||||
let parsed_output = String::from_utf8(output.stdout).unwrap();
|
for distribution in output.stdout.trim().lines() {
|
||||||
for distribution in parsed_output.trim().split('\n') {
|
|
||||||
debug!("Bedrock distribution {}", distribution);
|
debug!("Bedrock distribution {}", distribution);
|
||||||
match distribution {
|
match distribution {
|
||||||
"arch" => archlinux::upgrade_arch_linux(ctx)?,
|
"arch" => archlinux::upgrade_arch_linux(ctx)?,
|
||||||
@@ -148,7 +149,7 @@ fn update_bedrock(ctx: &ExecutionContext) -> Result<()> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn is_wsl() -> Result<bool> {
|
fn is_wsl() -> Result<bool> {
|
||||||
let output = Command::new("uname").arg("-r").check_output()?;
|
let output = Command::new("uname").arg("-r").output_checked_utf8()?.stdout;
|
||||||
debug!("Uname output: {}", output);
|
debug!("Uname output: {}", output);
|
||||||
Ok(output.contains("microsoft"))
|
Ok(output.contains("microsoft"))
|
||||||
}
|
}
|
||||||
@@ -157,8 +158,8 @@ fn upgrade_alpine_linux(ctx: &ExecutionContext) -> Result<()> {
|
|||||||
let apk = require("apk")?;
|
let apk = require("apk")?;
|
||||||
let sudo = ctx.sudo().as_ref().unwrap();
|
let sudo = ctx.sudo().as_ref().unwrap();
|
||||||
|
|
||||||
ctx.run_type().execute(sudo).arg(&apk).arg("update").check_run()?;
|
ctx.run_type().execute(sudo).arg(&apk).arg("update").status_checked()?;
|
||||||
ctx.run_type().execute(sudo).arg(&apk).arg("upgrade").check_run()
|
ctx.run_type().execute(sudo).arg(&apk).arg("upgrade").status_checked()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn upgrade_redhat(ctx: &ExecutionContext) -> Result<()> {
|
fn upgrade_redhat(ctx: &ExecutionContext) -> Result<()> {
|
||||||
@@ -166,7 +167,7 @@ fn upgrade_redhat(ctx: &ExecutionContext) -> Result<()> {
|
|||||||
if ctx.config().rpm_ostree() {
|
if ctx.config().rpm_ostree() {
|
||||||
let mut command = ctx.run_type().execute(ostree);
|
let mut command = ctx.run_type().execute(ostree);
|
||||||
command.arg("upgrade");
|
command.arg("upgrade");
|
||||||
return command.check_run();
|
return command.status_checked();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -188,7 +189,7 @@ fn upgrade_redhat(ctx: &ExecutionContext) -> Result<()> {
|
|||||||
command.arg("-y");
|
command.arg("-y");
|
||||||
}
|
}
|
||||||
|
|
||||||
command.check_run()?;
|
command.status_checked()?;
|
||||||
} else {
|
} else {
|
||||||
print_warning("No sudo detected. Skipping system upgrade");
|
print_warning("No sudo detected. Skipping system upgrade");
|
||||||
}
|
}
|
||||||
@@ -198,7 +199,7 @@ fn upgrade_redhat(ctx: &ExecutionContext) -> Result<()> {
|
|||||||
|
|
||||||
fn upgrade_bedrock_strata(ctx: &ExecutionContext) -> Result<()> {
|
fn upgrade_bedrock_strata(ctx: &ExecutionContext) -> Result<()> {
|
||||||
if let Some(sudo) = ctx.sudo() {
|
if let Some(sudo) = ctx.sudo() {
|
||||||
ctx.run_type().execute(sudo).args(["brl", "update"]).check_run()?;
|
ctx.run_type().execute(sudo).args(["brl", "update"]).status_checked()?;
|
||||||
} else {
|
} else {
|
||||||
print_warning("No sudo detected. Skipping system upgrade");
|
print_warning("No sudo detected. Skipping system upgrade");
|
||||||
}
|
}
|
||||||
@@ -208,12 +209,15 @@ fn upgrade_bedrock_strata(ctx: &ExecutionContext) -> Result<()> {
|
|||||||
|
|
||||||
fn upgrade_suse(ctx: &ExecutionContext) -> Result<()> {
|
fn upgrade_suse(ctx: &ExecutionContext) -> Result<()> {
|
||||||
if let Some(sudo) = ctx.sudo() {
|
if let Some(sudo) = ctx.sudo() {
|
||||||
ctx.run_type().execute(sudo).args(["zypper", "refresh"]).check_run()?;
|
ctx.run_type()
|
||||||
|
.execute(sudo)
|
||||||
|
.args(["zypper", "refresh"])
|
||||||
|
.status_checked()?;
|
||||||
|
|
||||||
ctx.run_type()
|
ctx.run_type()
|
||||||
.execute(sudo)
|
.execute(sudo)
|
||||||
.args(["zypper", "dist-upgrade"])
|
.args(["zypper", "dist-upgrade"])
|
||||||
.check_run()?;
|
.status_checked()?;
|
||||||
} else {
|
} else {
|
||||||
print_warning("No sudo detected. Skipping system upgrade");
|
print_warning("No sudo detected. Skipping system upgrade");
|
||||||
}
|
}
|
||||||
@@ -235,7 +239,7 @@ fn upgrade_openmandriva(ctx: &ExecutionContext) -> Result<()> {
|
|||||||
command.arg("-y");
|
command.arg("-y");
|
||||||
}
|
}
|
||||||
|
|
||||||
command.check_run()?;
|
command.status_checked()?;
|
||||||
} else {
|
} else {
|
||||||
print_warning("No sudo detected. Skipping system upgrade");
|
print_warning("No sudo detected. Skipping system upgrade");
|
||||||
}
|
}
|
||||||
@@ -250,14 +254,14 @@ fn upgrade_void(ctx: &ExecutionContext) -> Result<()> {
|
|||||||
if ctx.config().yes(Step::System) {
|
if ctx.config().yes(Step::System) {
|
||||||
command.arg("-y");
|
command.arg("-y");
|
||||||
}
|
}
|
||||||
command.check_run()?;
|
command.status_checked()?;
|
||||||
|
|
||||||
let mut command = ctx.run_type().execute(sudo);
|
let mut command = ctx.run_type().execute(sudo);
|
||||||
command.args(["xbps-install", "-u"]);
|
command.args(["xbps-install", "-u"]);
|
||||||
if ctx.config().yes(Step::System) {
|
if ctx.config().yes(Step::System) {
|
||||||
command.arg("-y");
|
command.arg("-y");
|
||||||
}
|
}
|
||||||
command.check_run()?;
|
command.status_checked()?;
|
||||||
} else {
|
} else {
|
||||||
print_warning("No sudo detected. Skipping system upgrade");
|
print_warning("No sudo detected. Skipping system upgrade");
|
||||||
}
|
}
|
||||||
@@ -270,7 +274,11 @@ fn upgrade_gentoo(ctx: &ExecutionContext) -> Result<()> {
|
|||||||
|
|
||||||
if let Some(sudo) = &ctx.sudo() {
|
if let Some(sudo) = &ctx.sudo() {
|
||||||
if let Some(layman) = which("layman") {
|
if let Some(layman) = which("layman") {
|
||||||
run_type.execute(sudo).arg(layman).args(["-s", "ALL"]).check_run()?;
|
run_type
|
||||||
|
.execute(sudo)
|
||||||
|
.arg(layman)
|
||||||
|
.args(["-s", "ALL"])
|
||||||
|
.status_checked()?;
|
||||||
}
|
}
|
||||||
|
|
||||||
println!("Syncing portage");
|
println!("Syncing portage");
|
||||||
@@ -283,10 +291,10 @@ fn upgrade_gentoo(ctx: &ExecutionContext) -> Result<()> {
|
|||||||
.map(|s| s.split_whitespace().collect())
|
.map(|s| s.split_whitespace().collect())
|
||||||
.unwrap_or_else(|| vec!["-q"]),
|
.unwrap_or_else(|| vec!["-q"]),
|
||||||
)
|
)
|
||||||
.check_run()?;
|
.status_checked()?;
|
||||||
|
|
||||||
if let Some(eix_update) = which("eix-update") {
|
if let Some(eix_update) = which("eix-update") {
|
||||||
run_type.execute(sudo).arg(eix_update).check_run()?;
|
run_type.execute(sudo).arg(eix_update).status_checked()?;
|
||||||
}
|
}
|
||||||
|
|
||||||
run_type
|
run_type
|
||||||
@@ -298,7 +306,7 @@ fn upgrade_gentoo(ctx: &ExecutionContext) -> Result<()> {
|
|||||||
.map(|s| s.split_whitespace().collect())
|
.map(|s| s.split_whitespace().collect())
|
||||||
.unwrap_or_else(|| vec!["-uDNa", "--with-bdeps=y", "world"]),
|
.unwrap_or_else(|| vec!["-uDNa", "--with-bdeps=y", "world"]),
|
||||||
)
|
)
|
||||||
.check_run()?;
|
.status_checked()?;
|
||||||
} else {
|
} else {
|
||||||
print_warning("No sudo detected. Skipping system upgrade");
|
print_warning("No sudo detected. Skipping system upgrade");
|
||||||
}
|
}
|
||||||
@@ -314,7 +322,7 @@ fn upgrade_debian(ctx: &ExecutionContext) -> Result<()> {
|
|||||||
|
|
||||||
let is_nala = apt.ends_with("nala");
|
let is_nala = apt.ends_with("nala");
|
||||||
if !is_nala {
|
if !is_nala {
|
||||||
ctx.run_type().execute(sudo).arg(&apt).arg("update").check_run()?;
|
ctx.run_type().execute(sudo).arg(&apt).arg("update").status_checked()?;
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut command = ctx.run_type().execute(sudo);
|
let mut command = ctx.run_type().execute(sudo);
|
||||||
@@ -330,17 +338,17 @@ fn upgrade_debian(ctx: &ExecutionContext) -> Result<()> {
|
|||||||
if let Some(args) = ctx.config().apt_arguments() {
|
if let Some(args) = ctx.config().apt_arguments() {
|
||||||
command.args(args.split_whitespace());
|
command.args(args.split_whitespace());
|
||||||
}
|
}
|
||||||
command.check_run()?;
|
command.status_checked()?;
|
||||||
|
|
||||||
if ctx.config().cleanup() {
|
if ctx.config().cleanup() {
|
||||||
ctx.run_type().execute(sudo).arg(&apt).arg("clean").check_run()?;
|
ctx.run_type().execute(sudo).arg(&apt).arg("clean").status_checked()?;
|
||||||
|
|
||||||
let mut command = ctx.run_type().execute(sudo);
|
let mut command = ctx.run_type().execute(sudo);
|
||||||
command.arg(&apt).arg("autoremove");
|
command.arg(&apt).arg("autoremove");
|
||||||
if ctx.config().yes(Step::System) {
|
if ctx.config().yes(Step::System) {
|
||||||
command.arg("-y");
|
command.arg("-y");
|
||||||
}
|
}
|
||||||
command.check_run()?;
|
command.status_checked()?;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
print_warning("No sudo detected. Skipping system upgrade");
|
print_warning("No sudo detected. Skipping system upgrade");
|
||||||
@@ -354,11 +362,11 @@ pub fn run_deb_get(ctx: &ExecutionContext) -> Result<()> {
|
|||||||
|
|
||||||
print_separator("deb-get");
|
print_separator("deb-get");
|
||||||
|
|
||||||
ctx.execute_elevated(&deb_get, false)?.arg("update").check_run()?;
|
ctx.execute_elevated(&deb_get, false)?.arg("update").status_checked()?;
|
||||||
ctx.execute_elevated(&deb_get, false)?.arg("upgrade").check_run()?;
|
ctx.execute_elevated(&deb_get, false)?.arg("upgrade").status_checked()?;
|
||||||
|
|
||||||
if ctx.config().cleanup() {
|
if ctx.config().cleanup() {
|
||||||
ctx.execute_elevated(&deb_get, false)?.arg("clean").check_run()?;
|
ctx.execute_elevated(&deb_get, false)?.arg("clean").status_checked()?;
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
@@ -366,7 +374,10 @@ pub fn run_deb_get(ctx: &ExecutionContext) -> Result<()> {
|
|||||||
|
|
||||||
fn upgrade_solus(ctx: &ExecutionContext) -> Result<()> {
|
fn upgrade_solus(ctx: &ExecutionContext) -> Result<()> {
|
||||||
if let Some(sudo) = ctx.sudo() {
|
if let Some(sudo) = ctx.sudo() {
|
||||||
ctx.run_type().execute(sudo).args(["eopkg", "upgrade"]).check_run()?;
|
ctx.run_type()
|
||||||
|
.execute(sudo)
|
||||||
|
.args(["eopkg", "upgrade"])
|
||||||
|
.status_checked()?;
|
||||||
} else {
|
} else {
|
||||||
print_warning("No sudo detected. Skipping system upgrade");
|
print_warning("No sudo detected. Skipping system upgrade");
|
||||||
}
|
}
|
||||||
@@ -379,10 +390,10 @@ pub fn run_pacdef(ctx: &ExecutionContext) -> Result<()> {
|
|||||||
|
|
||||||
print_separator("pacdef");
|
print_separator("pacdef");
|
||||||
|
|
||||||
ctx.run_type().execute(&pacdef).arg("sync").check_run()?;
|
ctx.run_type().execute(&pacdef).arg("sync").status_checked()?;
|
||||||
|
|
||||||
println!();
|
println!();
|
||||||
ctx.run_type().execute(&pacdef).arg("review").check_run()
|
ctx.run_type().execute(&pacdef).arg("review").status_checked()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn run_pacstall(ctx: &ExecutionContext) -> Result<()> {
|
pub fn run_pacstall(ctx: &ExecutionContext) -> Result<()> {
|
||||||
@@ -390,13 +401,16 @@ pub fn run_pacstall(ctx: &ExecutionContext) -> Result<()> {
|
|||||||
|
|
||||||
print_separator("Pacstall");
|
print_separator("Pacstall");
|
||||||
|
|
||||||
ctx.run_type().execute(&pacstall).arg("-U").check_run()?;
|
ctx.run_type().execute(&pacstall).arg("-U").status_checked()?;
|
||||||
ctx.run_type().execute(pacstall).arg("-Up").check_run()
|
ctx.run_type().execute(pacstall).arg("-Up").status_checked()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn upgrade_clearlinux(ctx: &ExecutionContext) -> Result<()> {
|
fn upgrade_clearlinux(ctx: &ExecutionContext) -> Result<()> {
|
||||||
if let Some(sudo) = &ctx.sudo() {
|
if let Some(sudo) = &ctx.sudo() {
|
||||||
ctx.run_type().execute(sudo).args(["swupd", "update"]).check_run()?;
|
ctx.run_type()
|
||||||
|
.execute(sudo)
|
||||||
|
.args(["swupd", "update"])
|
||||||
|
.status_checked()?;
|
||||||
} else {
|
} else {
|
||||||
print_warning("No sudo detected. Skipping system upgrade");
|
print_warning("No sudo detected. Skipping system upgrade");
|
||||||
}
|
}
|
||||||
@@ -406,26 +420,29 @@ fn upgrade_clearlinux(ctx: &ExecutionContext) -> Result<()> {
|
|||||||
|
|
||||||
fn upgrade_exherbo(ctx: &ExecutionContext) -> Result<()> {
|
fn upgrade_exherbo(ctx: &ExecutionContext) -> Result<()> {
|
||||||
if let Some(sudo) = ctx.sudo() {
|
if let Some(sudo) = ctx.sudo() {
|
||||||
ctx.run_type().execute(sudo).args(["cave", "sync"]).check_run()?;
|
ctx.run_type().execute(sudo).args(["cave", "sync"]).status_checked()?;
|
||||||
|
|
||||||
ctx.run_type()
|
ctx.run_type()
|
||||||
.execute(sudo)
|
.execute(sudo)
|
||||||
.args(["cave", "resolve", "world", "-c1", "-Cs", "-km", "-Km", "-x"])
|
.args(["cave", "resolve", "world", "-c1", "-Cs", "-km", "-Km", "-x"])
|
||||||
.check_run()?;
|
.status_checked()?;
|
||||||
|
|
||||||
if ctx.config().cleanup() {
|
if ctx.config().cleanup() {
|
||||||
ctx.run_type().execute(sudo).args(["cave", "purge", "-x"]).check_run()?;
|
ctx.run_type()
|
||||||
|
.execute(sudo)
|
||||||
|
.args(["cave", "purge", "-x"])
|
||||||
|
.status_checked()?;
|
||||||
}
|
}
|
||||||
|
|
||||||
ctx.run_type()
|
ctx.run_type()
|
||||||
.execute(sudo)
|
.execute(sudo)
|
||||||
.args(["cave", "fix-linkage", "-x", "--", "-Cs"])
|
.args(["cave", "fix-linkage", "-x", "--", "-Cs"])
|
||||||
.check_run()?;
|
.status_checked()?;
|
||||||
|
|
||||||
ctx.run_type()
|
ctx.run_type()
|
||||||
.execute(sudo)
|
.execute(sudo)
|
||||||
.args(["eclectic", "config", "interactive"])
|
.args(["eclectic", "config", "interactive"])
|
||||||
.check_run()?;
|
.status_checked()?;
|
||||||
} else {
|
} else {
|
||||||
print_warning("No sudo detected. Skipping system upgrade");
|
print_warning("No sudo detected. Skipping system upgrade");
|
||||||
}
|
}
|
||||||
@@ -438,13 +455,13 @@ fn upgrade_nixos(ctx: &ExecutionContext) -> Result<()> {
|
|||||||
ctx.run_type()
|
ctx.run_type()
|
||||||
.execute(sudo)
|
.execute(sudo)
|
||||||
.args(["/run/current-system/sw/bin/nixos-rebuild", "switch", "--upgrade"])
|
.args(["/run/current-system/sw/bin/nixos-rebuild", "switch", "--upgrade"])
|
||||||
.check_run()?;
|
.status_checked()?;
|
||||||
|
|
||||||
if ctx.config().cleanup() {
|
if ctx.config().cleanup() {
|
||||||
ctx.run_type()
|
ctx.run_type()
|
||||||
.execute(sudo)
|
.execute(sudo)
|
||||||
.args(["/run/current-system/sw/bin/nix-collect-garbage", "-d"])
|
.args(["/run/current-system/sw/bin/nix-collect-garbage", "-d"])
|
||||||
.check_run()?;
|
.status_checked()?;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
print_warning("No sudo detected. Skipping system upgrade");
|
print_warning("No sudo detected. Skipping system upgrade");
|
||||||
@@ -462,7 +479,11 @@ fn upgrade_neon(ctx: &ExecutionContext) -> Result<()> {
|
|||||||
if let Some(sudo) = &ctx.sudo() {
|
if let Some(sudo) = &ctx.sudo() {
|
||||||
let pkcon = which("pkcon").unwrap();
|
let pkcon = which("pkcon").unwrap();
|
||||||
// pkcon ignores update with update and refresh provided together
|
// pkcon ignores update with update and refresh provided together
|
||||||
ctx.run_type().execute(sudo).arg(&pkcon).arg("refresh").check_run()?;
|
ctx.run_type()
|
||||||
|
.execute(sudo)
|
||||||
|
.arg(&pkcon)
|
||||||
|
.arg("refresh")
|
||||||
|
.status_checked()?;
|
||||||
let mut exe = ctx.run_type().execute(sudo);
|
let mut exe = ctx.run_type().execute(sudo);
|
||||||
let cmd = exe.arg(&pkcon).arg("update");
|
let cmd = exe.arg(&pkcon).arg("update");
|
||||||
if ctx.config().yes(Step::System) {
|
if ctx.config().yes(Step::System) {
|
||||||
@@ -472,13 +493,13 @@ fn upgrade_neon(ctx: &ExecutionContext) -> Result<()> {
|
|||||||
cmd.arg("--autoremove");
|
cmd.arg("--autoremove");
|
||||||
}
|
}
|
||||||
// from pkcon man, exit code 5 is 'Nothing useful was done.'
|
// from pkcon man, exit code 5 is 'Nothing useful was done.'
|
||||||
cmd.check_run_with_codes(&[5])?;
|
cmd.status_checked_with_codes(&[5])?;
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn run_needrestart(sudo: Option<&PathBuf>, run_type: RunType) -> Result<()> {
|
pub fn run_needrestart(sudo: Option<&Sudo>, run_type: RunType) -> Result<()> {
|
||||||
let sudo = require_option(sudo, String::from("sudo is not installed"))?;
|
let sudo = require_option(sudo, String::from("sudo is not installed"))?;
|
||||||
let needrestart = require("needrestart")?;
|
let needrestart = require("needrestart")?;
|
||||||
let distribution = Distribution::detect()?;
|
let distribution = Distribution::detect()?;
|
||||||
@@ -489,7 +510,7 @@ pub fn run_needrestart(sudo: Option<&PathBuf>, run_type: RunType) -> Result<()>
|
|||||||
|
|
||||||
print_separator("Check for needed restarts");
|
print_separator("Check for needed restarts");
|
||||||
|
|
||||||
run_type.execute(sudo).arg(needrestart).check_run()?;
|
run_type.execute(sudo).arg(needrestart).status_checked()?;
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
@@ -506,7 +527,7 @@ pub fn run_fwupdmgr(ctx: &ExecutionContext) -> Result<()> {
|
|||||||
ctx.run_type()
|
ctx.run_type()
|
||||||
.execute(&fwupdmgr)
|
.execute(&fwupdmgr)
|
||||||
.arg("refresh")
|
.arg("refresh")
|
||||||
.check_run_with_codes(&[2])?;
|
.status_checked_with_codes(&[2])?;
|
||||||
|
|
||||||
let mut updmgr = ctx.run_type().execute(&fwupdmgr);
|
let mut updmgr = ctx.run_type().execute(&fwupdmgr);
|
||||||
|
|
||||||
@@ -518,7 +539,7 @@ pub fn run_fwupdmgr(ctx: &ExecutionContext) -> Result<()> {
|
|||||||
} else {
|
} else {
|
||||||
updmgr.arg("get-updates");
|
updmgr.arg("get-updates");
|
||||||
}
|
}
|
||||||
updmgr.check_run_with_codes(&[2])
|
updmgr.status_checked_with_codes(&[2])
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn flatpak_update(ctx: &ExecutionContext) -> Result<()> {
|
pub fn flatpak_update(ctx: &ExecutionContext) -> Result<()> {
|
||||||
@@ -533,14 +554,14 @@ pub fn flatpak_update(ctx: &ExecutionContext) -> Result<()> {
|
|||||||
if yes {
|
if yes {
|
||||||
update_args.push("-y");
|
update_args.push("-y");
|
||||||
}
|
}
|
||||||
run_type.execute(&flatpak).args(&update_args).check_run()?;
|
run_type.execute(&flatpak).args(&update_args).status_checked()?;
|
||||||
|
|
||||||
if cleanup {
|
if cleanup {
|
||||||
let mut cleanup_args = vec!["uninstall", "--user", "--unused"];
|
let mut cleanup_args = vec!["uninstall", "--user", "--unused"];
|
||||||
if yes {
|
if yes {
|
||||||
cleanup_args.push("-y");
|
cleanup_args.push("-y");
|
||||||
}
|
}
|
||||||
run_type.execute(&flatpak).args(&cleanup_args).check_run()?;
|
run_type.execute(&flatpak).args(&cleanup_args).status_checked()?;
|
||||||
}
|
}
|
||||||
|
|
||||||
print_separator("Flatpak System Packages");
|
print_separator("Flatpak System Packages");
|
||||||
@@ -549,33 +570,41 @@ pub fn flatpak_update(ctx: &ExecutionContext) -> Result<()> {
|
|||||||
if yes {
|
if yes {
|
||||||
update_args.push("-y");
|
update_args.push("-y");
|
||||||
}
|
}
|
||||||
run_type.execute(sudo).arg(&flatpak).args(&update_args).check_run()?;
|
run_type
|
||||||
|
.execute(sudo)
|
||||||
|
.arg(&flatpak)
|
||||||
|
.args(&update_args)
|
||||||
|
.status_checked()?;
|
||||||
if cleanup {
|
if cleanup {
|
||||||
let mut cleanup_args = vec!["uninstall", "--system", "--unused"];
|
let mut cleanup_args = vec!["uninstall", "--system", "--unused"];
|
||||||
if yes {
|
if yes {
|
||||||
cleanup_args.push("-y");
|
cleanup_args.push("-y");
|
||||||
}
|
}
|
||||||
run_type.execute(sudo).arg(flatpak).args(&cleanup_args).check_run()?;
|
run_type
|
||||||
|
.execute(sudo)
|
||||||
|
.arg(flatpak)
|
||||||
|
.args(&cleanup_args)
|
||||||
|
.status_checked()?;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
let mut update_args = vec!["update", "--system"];
|
let mut update_args = vec!["update", "--system"];
|
||||||
if yes {
|
if yes {
|
||||||
update_args.push("-y");
|
update_args.push("-y");
|
||||||
}
|
}
|
||||||
run_type.execute(&flatpak).args(&update_args).check_run()?;
|
run_type.execute(&flatpak).args(&update_args).status_checked()?;
|
||||||
if cleanup {
|
if cleanup {
|
||||||
let mut cleanup_args = vec!["uninstall", "--system", "--unused"];
|
let mut cleanup_args = vec!["uninstall", "--system", "--unused"];
|
||||||
if yes {
|
if yes {
|
||||||
cleanup_args.push("-y");
|
cleanup_args.push("-y");
|
||||||
}
|
}
|
||||||
run_type.execute(flatpak).args(&cleanup_args).check_run()?;
|
run_type.execute(flatpak).args(&cleanup_args).status_checked()?;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn run_snap(sudo: Option<&PathBuf>, run_type: RunType) -> Result<()> {
|
pub fn run_snap(sudo: Option<&Sudo>, run_type: RunType) -> Result<()> {
|
||||||
let sudo = require_option(sudo, String::from("sudo is not installed"))?;
|
let sudo = require_option(sudo, String::from("sudo is not installed"))?;
|
||||||
let snap = require("snap")?;
|
let snap = require("snap")?;
|
||||||
|
|
||||||
@@ -584,17 +613,17 @@ pub fn run_snap(sudo: Option<&PathBuf>, run_type: RunType) -> Result<()> {
|
|||||||
}
|
}
|
||||||
print_separator("snap");
|
print_separator("snap");
|
||||||
|
|
||||||
run_type.execute(sudo).arg(snap).arg("refresh").check_run()
|
run_type.execute(sudo).arg(snap).arg("refresh").status_checked()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn run_pihole_update(sudo: Option<&PathBuf>, run_type: RunType) -> Result<()> {
|
pub fn run_pihole_update(sudo: Option<&Sudo>, run_type: RunType) -> Result<()> {
|
||||||
let sudo = require_option(sudo, String::from("sudo is not installed"))?;
|
let sudo = require_option(sudo, String::from("sudo is not installed"))?;
|
||||||
let pihole = require("pihole")?;
|
let pihole = require("pihole")?;
|
||||||
Path::new("/opt/pihole/update.sh").require()?;
|
Path::new("/opt/pihole/update.sh").require()?;
|
||||||
|
|
||||||
print_separator("pihole");
|
print_separator("pihole");
|
||||||
|
|
||||||
run_type.execute(sudo).arg(pihole).arg("-up").check_run()
|
run_type.execute(sudo).arg(pihole).arg("-up").status_checked()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn run_protonup_update(ctx: &ExecutionContext) -> Result<()> {
|
pub fn run_protonup_update(ctx: &ExecutionContext) -> Result<()> {
|
||||||
@@ -602,15 +631,17 @@ pub fn run_protonup_update(ctx: &ExecutionContext) -> Result<()> {
|
|||||||
|
|
||||||
print_separator("protonup");
|
print_separator("protonup");
|
||||||
|
|
||||||
ctx.run_type().execute(protonup).check_run()?;
|
ctx.run_type().execute(protonup).status_checked()?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn run_distrobox_update(ctx: &ExecutionContext) -> Result<()> {
|
pub fn run_distrobox_update(ctx: &ExecutionContext) -> Result<()> {
|
||||||
|
let distrobox = require("distrobox")?;
|
||||||
|
|
||||||
print_separator("Distrobox");
|
print_separator("Distrobox");
|
||||||
match (
|
match (
|
||||||
match (
|
match (
|
||||||
ctx.run_type().execute("distrobox").arg("upgrade"),
|
ctx.run_type().execute(distrobox).arg("upgrade"),
|
||||||
ctx.config().distrobox_containers(),
|
ctx.config().distrobox_containers(),
|
||||||
) {
|
) {
|
||||||
(r, Some(c)) => {
|
(r, Some(c)) => {
|
||||||
@@ -626,7 +657,7 @@ pub fn run_distrobox_update(ctx: &ExecutionContext) -> Result<()> {
|
|||||||
(r, true) => r.arg("--root"),
|
(r, true) => r.arg("--root"),
|
||||||
(r, false) => r,
|
(r, false) => r,
|
||||||
}
|
}
|
||||||
.check_run()
|
.status_checked()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn run_config_update(ctx: &ExecutionContext) -> Result<()> {
|
pub fn run_config_update(ctx: &ExecutionContext) -> Result<()> {
|
||||||
@@ -637,14 +668,14 @@ pub fn run_config_update(ctx: &ExecutionContext) -> Result<()> {
|
|||||||
|
|
||||||
if let Ok(etc_update) = require("etc-update") {
|
if let Ok(etc_update) = require("etc-update") {
|
||||||
print_separator("Configuration update");
|
print_separator("Configuration update");
|
||||||
ctx.run_type().execute(sudo).arg(etc_update).check_run()?;
|
ctx.run_type().execute(sudo).arg(etc_update).status_checked()?;
|
||||||
} else if let Ok(pacdiff) = require("pacdiff") {
|
} else if let Ok(pacdiff) = require("pacdiff") {
|
||||||
if std::env::var("DIFFPROG").is_err() {
|
if std::env::var("DIFFPROG").is_err() {
|
||||||
require("vim")?;
|
require("vim")?;
|
||||||
}
|
}
|
||||||
|
|
||||||
print_separator("Configuration update");
|
print_separator("Configuration update");
|
||||||
ctx.execute_elevated(&pacdiff, false)?.check_run()?;
|
ctx.execute_elevated(&pacdiff, false)?.status_checked()?;
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
|
|||||||
@@ -1,26 +1,30 @@
|
|||||||
|
use crate::command::CommandExt;
|
||||||
use crate::execution_context::ExecutionContext;
|
use crate::execution_context::ExecutionContext;
|
||||||
use crate::executor::{CommandExt, RunType};
|
use crate::executor::RunType;
|
||||||
use crate::terminal::{print_separator, prompt_yesno};
|
use crate::terminal::{print_separator, prompt_yesno};
|
||||||
use crate::{error::TopgradeError, utils::require, Step};
|
use crate::{utils::require, Step};
|
||||||
use anyhow::Result;
|
use color_eyre::eyre::Result;
|
||||||
use log::debug;
|
|
||||||
use std::fs;
|
use std::fs;
|
||||||
use std::process::Command;
|
use std::process::Command;
|
||||||
|
use tracing::debug;
|
||||||
|
|
||||||
pub fn run_macports(ctx: &ExecutionContext) -> Result<()> {
|
pub fn run_macports(ctx: &ExecutionContext) -> Result<()> {
|
||||||
require("port")?;
|
require("port")?;
|
||||||
let sudo = ctx.sudo().as_ref().unwrap();
|
let sudo = ctx.sudo().as_ref().unwrap();
|
||||||
print_separator("MacPorts");
|
print_separator("MacPorts");
|
||||||
ctx.run_type().execute(sudo).args(["port", "selfupdate"]).check_run()?;
|
ctx.run_type()
|
||||||
|
.execute(sudo)
|
||||||
|
.args(["port", "selfupdate"])
|
||||||
|
.status_checked()?;
|
||||||
ctx.run_type()
|
ctx.run_type()
|
||||||
.execute(sudo)
|
.execute(sudo)
|
||||||
.args(["port", "-u", "upgrade", "outdated"])
|
.args(["port", "-u", "upgrade", "outdated"])
|
||||||
.check_run()?;
|
.status_checked()?;
|
||||||
if ctx.config().cleanup() {
|
if ctx.config().cleanup() {
|
||||||
ctx.run_type()
|
ctx.run_type()
|
||||||
.execute(sudo)
|
.execute(sudo)
|
||||||
.args(["port", "-N", "reclaim"])
|
.args(["port", "-N", "reclaim"])
|
||||||
.check_run()?;
|
.status_checked()?;
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
@@ -30,7 +34,7 @@ pub fn run_mas(run_type: RunType) -> Result<()> {
|
|||||||
let mas = require("mas")?;
|
let mas = require("mas")?;
|
||||||
print_separator("macOS App Store");
|
print_separator("macOS App Store");
|
||||||
|
|
||||||
run_type.execute(mas).arg("upgrade").check_run()
|
run_type.execute(mas).arg("upgrade").status_checked()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn upgrade_macos(ctx: &ExecutionContext) -> Result<()> {
|
pub fn upgrade_macos(ctx: &ExecutionContext) -> Result<()> {
|
||||||
@@ -58,20 +62,15 @@ pub fn upgrade_macos(ctx: &ExecutionContext) -> Result<()> {
|
|||||||
command.arg("--no-scan");
|
command.arg("--no-scan");
|
||||||
}
|
}
|
||||||
|
|
||||||
command.check_run()
|
command.status_checked()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn system_update_available() -> Result<bool> {
|
fn system_update_available() -> Result<bool> {
|
||||||
let output = Command::new("softwareupdate").arg("--list").output()?;
|
let output = Command::new("softwareupdate").arg("--list").output_checked_utf8()?;
|
||||||
|
|
||||||
debug!("{:?}", output);
|
debug!("{:?}", output);
|
||||||
|
|
||||||
let status = output.status;
|
Ok(!output.stderr.contains("No new software available"))
|
||||||
if !status.success() {
|
|
||||||
return Err(TopgradeError::ProcessFailed(status).into());
|
|
||||||
}
|
|
||||||
let string_output = String::from_utf8(output.stderr)?;
|
|
||||||
debug!("{:?}", string_output);
|
|
||||||
Ok(!string_output.contains("No new software available"))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn run_sparkle(ctx: &ExecutionContext) -> Result<()> {
|
pub fn run_sparkle(ctx: &ExecutionContext) -> Result<()> {
|
||||||
@@ -83,12 +82,12 @@ pub fn run_sparkle(ctx: &ExecutionContext) -> Result<()> {
|
|||||||
let probe = Command::new(&sparkle)
|
let probe = Command::new(&sparkle)
|
||||||
.args(["--probe", "--application"])
|
.args(["--probe", "--application"])
|
||||||
.arg(application.path())
|
.arg(application.path())
|
||||||
.check_output();
|
.output_checked_utf8();
|
||||||
if probe.is_ok() {
|
if probe.is_ok() {
|
||||||
let mut command = ctx.run_type().execute(&sparkle);
|
let mut command = ctx.run_type().execute(&sparkle);
|
||||||
command.args(["bundle", "--check-immediately", "--application"]);
|
command.args(["bundle", "--check-immediately", "--application"]);
|
||||||
command.arg(application.path());
|
command.arg(application.path());
|
||||||
command.spawn()?.wait()?;
|
command.status_checked()?;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
|
|||||||
@@ -1,17 +1,23 @@
|
|||||||
use crate::executor::RunType;
|
use crate::executor::RunType;
|
||||||
use crate::terminal::print_separator;
|
use crate::terminal::print_separator;
|
||||||
use crate::utils::require_option;
|
use crate::utils::require_option;
|
||||||
use anyhow::Result;
|
use color_eyre::eyre::Result;
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
|
|
||||||
pub fn upgrade_openbsd(sudo: Option<&PathBuf>, run_type: RunType) -> Result<()> {
|
pub fn upgrade_openbsd(sudo: Option<&PathBuf>, run_type: RunType) -> Result<()> {
|
||||||
let sudo = require_option(sudo, String::from("No sudo detected"))?;
|
let sudo = require_option(sudo, String::from("No sudo detected"))?;
|
||||||
print_separator("OpenBSD Update");
|
print_separator("OpenBSD Update");
|
||||||
run_type.execute(sudo).args(&["/usr/sbin/sysupgrade", "-n"]).check_run()
|
run_type
|
||||||
|
.execute(sudo)
|
||||||
|
.args(&["/usr/sbin/sysupgrade", "-n"])
|
||||||
|
.status_checked()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn upgrade_packages(sudo: Option<&PathBuf>, run_type: RunType) -> Result<()> {
|
pub fn upgrade_packages(sudo: Option<&PathBuf>, run_type: RunType) -> Result<()> {
|
||||||
let sudo = require_option(sudo, String::from("No sudo detected"))?;
|
let sudo = require_option(sudo, String::from("No sudo detected"))?;
|
||||||
print_separator("OpenBSD Packages");
|
print_separator("OpenBSD Packages");
|
||||||
run_type.execute(sudo).args(&["/usr/sbin/pkg_add", "-u"]).check_run()
|
run_type
|
||||||
|
.execute(sudo)
|
||||||
|
.args(&["/usr/sbin/pkg_add", "-u"])
|
||||||
|
.status_checked()
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,33 +1,43 @@
|
|||||||
use crate::error::{SkipStep, TopgradeError};
|
|
||||||
use crate::execution_context::ExecutionContext;
|
|
||||||
use crate::executor::{CommandExt, Executor, ExecutorExitStatus, RunType};
|
|
||||||
use crate::terminal::print_separator;
|
|
||||||
#[cfg(not(target_os = "macos"))]
|
|
||||||
use crate::utils::require_option;
|
|
||||||
use crate::utils::{require, PathExt};
|
|
||||||
use crate::Step;
|
|
||||||
use anyhow::Result;
|
|
||||||
use directories::BaseDirs;
|
|
||||||
use home;
|
|
||||||
use ini::Ini;
|
|
||||||
use log::debug;
|
|
||||||
use std::fs;
|
use std::fs;
|
||||||
use std::os::unix::fs::MetadataExt;
|
use std::os::unix::fs::MetadataExt;
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
use std::process::Command;
|
use std::process::Command;
|
||||||
use std::{env, path::Path};
|
use std::{env, path::Path};
|
||||||
|
|
||||||
|
use crate::command::CommandExt;
|
||||||
|
use crate::Step;
|
||||||
|
use color_eyre::eyre::Result;
|
||||||
|
use directories::BaseDirs;
|
||||||
|
use home;
|
||||||
|
use ini::Ini;
|
||||||
|
use tracing::debug;
|
||||||
|
|
||||||
|
use crate::error::SkipStep;
|
||||||
|
use crate::execution_context::ExecutionContext;
|
||||||
|
#[cfg(any(target_os = "linux", target_os = "macos"))]
|
||||||
|
use crate::executor::Executor;
|
||||||
|
use crate::executor::RunType;
|
||||||
|
use crate::terminal::print_separator;
|
||||||
|
#[cfg(not(any(target_os = "android", target_os = "macos")))]
|
||||||
|
use crate::utils::require_option;
|
||||||
|
use crate::utils::{require, PathExt};
|
||||||
|
|
||||||
|
#[cfg(any(target_os = "linux", target_os = "macos"))]
|
||||||
const INTEL_BREW: &str = "/usr/local/bin/brew";
|
const INTEL_BREW: &str = "/usr/local/bin/brew";
|
||||||
|
|
||||||
|
#[cfg(any(target_os = "linux", target_os = "macos"))]
|
||||||
const ARM_BREW: &str = "/opt/homebrew/bin/brew";
|
const ARM_BREW: &str = "/opt/homebrew/bin/brew";
|
||||||
|
|
||||||
#[derive(Copy, Clone, Debug)]
|
#[derive(Copy, Clone, Debug)]
|
||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
|
#[cfg(any(target_os = "linux", target_os = "macos"))]
|
||||||
pub enum BrewVariant {
|
pub enum BrewVariant {
|
||||||
Path,
|
Path,
|
||||||
MacIntel,
|
MacIntel,
|
||||||
MacArm,
|
MacArm,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(any(target_os = "linux", target_os = "macos"))]
|
||||||
impl BrewVariant {
|
impl BrewVariant {
|
||||||
fn binary_name(self) -> &'static str {
|
fn binary_name(self) -> &'static str {
|
||||||
match self {
|
match self {
|
||||||
@@ -77,30 +87,36 @@ impl BrewVariant {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn run_fisher(base_dirs: &BaseDirs, run_type: RunType) -> Result<()> {
|
pub fn run_fisher(run_type: RunType) -> Result<()> {
|
||||||
let fish = require("fish")?;
|
let fish = require("fish")?;
|
||||||
|
|
||||||
if env::var("fisher_path").is_err() {
|
Command::new(&fish)
|
||||||
base_dirs
|
.args(["-c", "type -t fisher"])
|
||||||
.home_dir()
|
.output_checked_utf8()
|
||||||
.join(".config/fish/functions/fisher.fish")
|
.map(|_| ())
|
||||||
.require()?;
|
.map_err(|_| SkipStep("`fisher` is not defined in `fish`".to_owned()))?;
|
||||||
}
|
|
||||||
|
Command::new(&fish)
|
||||||
|
.args(["-c", "echo \"$__fish_config_dir/fish_plugins\""])
|
||||||
|
.output_checked_utf8()
|
||||||
|
.and_then(|output| Path::new(&output.stdout.trim()).require().map(|_| ()))
|
||||||
|
.map_err(|err| SkipStep(format!("`fish_plugins` path doesn't exist: {err}")))?;
|
||||||
|
|
||||||
print_separator("Fisher");
|
print_separator("Fisher");
|
||||||
|
|
||||||
let version_str = run_type
|
let version_str = run_type
|
||||||
.execute(&fish)
|
.execute(&fish)
|
||||||
.args(["-c", "fisher --version"])
|
.args(["-c", "fisher --version"])
|
||||||
.check_output()?;
|
.output_checked_utf8()?
|
||||||
|
.stdout;
|
||||||
debug!("Fisher version: {}", version_str);
|
debug!("Fisher version: {}", version_str);
|
||||||
|
|
||||||
if version_str.starts_with("fisher version 3.") {
|
if version_str.starts_with("fisher version 3.") {
|
||||||
// v3 - see https://github.com/topgrade-rs/topgrade/pull/37#issuecomment-1283844506
|
// v3 - see https://github.com/topgrade-rs/topgrade/pull/37#issuecomment-1283844506
|
||||||
run_type.execute(&fish).args(["-c", "fisher"]).check_run()
|
run_type.execute(&fish).args(["-c", "fisher"]).status_checked()
|
||||||
} else {
|
} else {
|
||||||
// v4
|
// v4
|
||||||
run_type.execute(&fish).args(["-c", "fisher update"]).check_run()
|
run_type.execute(&fish).args(["-c", "fisher update"]).status_checked()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -112,7 +128,7 @@ pub fn run_bashit(ctx: &ExecutionContext) -> Result<()> {
|
|||||||
ctx.run_type()
|
ctx.run_type()
|
||||||
.execute("bash")
|
.execute("bash")
|
||||||
.args(["-lic", &format!("bash-it update {}", ctx.config().bashit_branch())])
|
.args(["-lic", &format!("bash-it update {}", ctx.config().bashit_branch())])
|
||||||
.check_run()
|
.status_checked()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn run_oh_my_fish(ctx: &ExecutionContext) -> Result<()> {
|
pub fn run_oh_my_fish(ctx: &ExecutionContext) -> Result<()> {
|
||||||
@@ -124,7 +140,7 @@ pub fn run_oh_my_fish(ctx: &ExecutionContext) -> Result<()> {
|
|||||||
|
|
||||||
print_separator("oh-my-fish");
|
print_separator("oh-my-fish");
|
||||||
|
|
||||||
ctx.run_type().execute(fish).args(["-c", "omf update"]).check_run()
|
ctx.run_type().execute(fish).args(["-c", "omf update"]).status_checked()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn run_pkgin(ctx: &ExecutionContext) -> Result<()> {
|
pub fn run_pkgin(ctx: &ExecutionContext) -> Result<()> {
|
||||||
@@ -135,14 +151,14 @@ pub fn run_pkgin(ctx: &ExecutionContext) -> Result<()> {
|
|||||||
if ctx.config().yes(Step::Pkgin) {
|
if ctx.config().yes(Step::Pkgin) {
|
||||||
command.arg("-y");
|
command.arg("-y");
|
||||||
}
|
}
|
||||||
command.check_run()?;
|
command.status_checked()?;
|
||||||
|
|
||||||
let mut command = ctx.run_type().execute(ctx.sudo().as_ref().unwrap());
|
let mut command = ctx.run_type().execute(ctx.sudo().as_ref().unwrap());
|
||||||
command.arg(&pkgin).arg("upgrade");
|
command.arg(&pkgin).arg("upgrade");
|
||||||
if ctx.config().yes(Step::Pkgin) {
|
if ctx.config().yes(Step::Pkgin) {
|
||||||
command.arg("-y");
|
command.arg("-y");
|
||||||
}
|
}
|
||||||
command.check_run()
|
command.status_checked()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn run_fish_plug(ctx: &ExecutionContext) -> Result<()> {
|
pub fn run_fish_plug(ctx: &ExecutionContext) -> Result<()> {
|
||||||
@@ -154,7 +170,10 @@ pub fn run_fish_plug(ctx: &ExecutionContext) -> Result<()> {
|
|||||||
|
|
||||||
print_separator("fish-plug");
|
print_separator("fish-plug");
|
||||||
|
|
||||||
ctx.run_type().execute(fish).args(["-c", "plug update"]).check_run()
|
ctx.run_type()
|
||||||
|
.execute(fish)
|
||||||
|
.args(["-c", "plug update"])
|
||||||
|
.status_checked()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Upgrades `fundle` and `fundle` plugins.
|
/// Upgrades `fundle` and `fundle` plugins.
|
||||||
@@ -171,7 +190,7 @@ pub fn run_fundle(ctx: &ExecutionContext) -> Result<()> {
|
|||||||
ctx.run_type()
|
ctx.run_type()
|
||||||
.execute(fish)
|
.execute(fish)
|
||||||
.args(["-c", "fundle self-update && fundle update"])
|
.args(["-c", "fundle self-update && fundle update"])
|
||||||
.check_run()
|
.status_checked()
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(not(any(target_os = "android", target_os = "macos")))]
|
#[cfg(not(any(target_os = "android", target_os = "macos")))]
|
||||||
@@ -192,10 +211,10 @@ pub fn upgrade_gnome_extensions(ctx: &ExecutionContext) -> Result<()> {
|
|||||||
"--method",
|
"--method",
|
||||||
"org.freedesktop.DBus.ListActivatableNames",
|
"org.freedesktop.DBus.ListActivatableNames",
|
||||||
])
|
])
|
||||||
.check_output()?;
|
.output_checked_utf8()?;
|
||||||
|
|
||||||
debug!("Checking for gnome extensions: {}", output);
|
debug!("Checking for gnome extensions: {}", output);
|
||||||
if !output.contains("org.gnome.Shell.Extensions") {
|
if !output.stdout.contains("org.gnome.Shell.Extensions") {
|
||||||
return Err(SkipStep(String::from("Gnome shell extensions are unregistered in DBus")).into());
|
return Err(SkipStep(String::from("Gnome shell extensions are unregistered in DBus")).into());
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -213,9 +232,10 @@ pub fn upgrade_gnome_extensions(ctx: &ExecutionContext) -> Result<()> {
|
|||||||
"--method",
|
"--method",
|
||||||
"org.gnome.Shell.Extensions.CheckForUpdates",
|
"org.gnome.Shell.Extensions.CheckForUpdates",
|
||||||
])
|
])
|
||||||
.check_run()
|
.status_checked()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(any(target_os = "linux", target_os = "macos"))]
|
||||||
pub fn run_brew_formula(ctx: &ExecutionContext, variant: BrewVariant) -> Result<()> {
|
pub fn run_brew_formula(ctx: &ExecutionContext, variant: BrewVariant) -> Result<()> {
|
||||||
#[allow(unused_variables)]
|
#[allow(unused_variables)]
|
||||||
let binary_name = require(variant.binary_name())?;
|
let binary_name = require(variant.binary_name())?;
|
||||||
@@ -230,18 +250,18 @@ pub fn run_brew_formula(ctx: &ExecutionContext, variant: BrewVariant) -> Result<
|
|||||||
print_separator(variant.step_title());
|
print_separator(variant.step_title());
|
||||||
let run_type = ctx.run_type();
|
let run_type = ctx.run_type();
|
||||||
|
|
||||||
variant.execute(run_type).arg("update").check_run()?;
|
variant.execute(run_type).arg("update").status_checked()?;
|
||||||
variant
|
variant
|
||||||
.execute(run_type)
|
.execute(run_type)
|
||||||
.args(["upgrade", "--ignore-pinned", "--formula"])
|
.args(["upgrade", "--ignore-pinned", "--formula"])
|
||||||
.check_run()?;
|
.status_checked()?;
|
||||||
|
|
||||||
if ctx.config().cleanup() {
|
if ctx.config().cleanup() {
|
||||||
variant.execute(run_type).arg("cleanup").check_run()?;
|
variant.execute(run_type).arg("cleanup").status_checked()?;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ctx.config().brew_autoremove() {
|
if ctx.config().brew_autoremove() {
|
||||||
variant.execute(run_type).arg("autoremove").check_run()?;
|
variant.execute(run_type).arg("autoremove").status_checked()?;
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
@@ -259,8 +279,8 @@ pub fn run_brew_cask(ctx: &ExecutionContext, variant: BrewVariant) -> Result<()>
|
|||||||
let cask_upgrade_exists = variant
|
let cask_upgrade_exists = variant
|
||||||
.execute(RunType::Wet)
|
.execute(RunType::Wet)
|
||||||
.args(["--repository", "buo/cask-upgrade"])
|
.args(["--repository", "buo/cask-upgrade"])
|
||||||
.check_output()
|
.output_checked_utf8()
|
||||||
.map(|p| Path::new(p.trim()).exists())?;
|
.map(|p| Path::new(p.stdout.trim()).exists())?;
|
||||||
|
|
||||||
let mut brew_args = vec![];
|
let mut brew_args = vec![];
|
||||||
|
|
||||||
@@ -276,10 +296,10 @@ pub fn run_brew_cask(ctx: &ExecutionContext, variant: BrewVariant) -> Result<()>
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
variant.execute(run_type).args(&brew_args).check_run()?;
|
variant.execute(run_type).args(&brew_args).status_checked()?;
|
||||||
|
|
||||||
if ctx.config().cleanup() {
|
if ctx.config().cleanup() {
|
||||||
variant.execute(run_type).arg("cleanup").check_run()?;
|
variant.execute(run_type).arg("cleanup").status_checked()?;
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
@@ -290,7 +310,7 @@ pub fn run_guix(ctx: &ExecutionContext) -> Result<()> {
|
|||||||
|
|
||||||
let run_type = ctx.run_type();
|
let run_type = ctx.run_type();
|
||||||
|
|
||||||
let output = Command::new(&guix).arg("pull").check_output();
|
let output = Command::new(&guix).arg("pull").output_checked_utf8();
|
||||||
debug!("guix pull output: {:?}", output);
|
debug!("guix pull output: {:?}", output);
|
||||||
let should_upgrade = output.is_ok();
|
let should_upgrade = output.is_ok();
|
||||||
debug!("Can Upgrade Guix: {:?}", should_upgrade);
|
debug!("Can Upgrade Guix: {:?}", should_upgrade);
|
||||||
@@ -298,7 +318,7 @@ pub fn run_guix(ctx: &ExecutionContext) -> Result<()> {
|
|||||||
print_separator("Guix");
|
print_separator("Guix");
|
||||||
|
|
||||||
if should_upgrade {
|
if should_upgrade {
|
||||||
return run_type.execute(&guix).args(["package", "-u"]).check_run();
|
return run_type.execute(&guix).args(["package", "-u"]).status_checked();
|
||||||
}
|
}
|
||||||
Err(SkipStep(String::from("Guix Pull Failed, Skipping")).into())
|
Err(SkipStep(String::from("Guix Pull Failed, Skipping")).into())
|
||||||
}
|
}
|
||||||
@@ -314,7 +334,7 @@ pub fn run_nix(ctx: &ExecutionContext) -> Result<()> {
|
|||||||
debug!("nix profile: {:?}", profile_path);
|
debug!("nix profile: {:?}", profile_path);
|
||||||
let manifest_json_path = profile_path.join("manifest.json");
|
let manifest_json_path = profile_path.join("manifest.json");
|
||||||
|
|
||||||
let output = Command::new(&nix_env).args(["--query", "nix"]).check_output();
|
let output = Command::new(&nix_env).args(["--query", "nix"]).output_checked_utf8();
|
||||||
debug!("nix-env output: {:?}", output);
|
debug!("nix-env output: {:?}", output);
|
||||||
let should_self_upgrade = output.is_ok();
|
let should_self_upgrade = output.is_ok();
|
||||||
|
|
||||||
@@ -346,13 +366,13 @@ pub fn run_nix(ctx: &ExecutionContext) -> Result<()> {
|
|||||||
|
|
||||||
if should_self_upgrade {
|
if should_self_upgrade {
|
||||||
if multi_user {
|
if multi_user {
|
||||||
ctx.execute_elevated(&nix, true)?.arg("upgrade-nix").check_run()?;
|
ctx.execute_elevated(&nix, true)?.arg("upgrade-nix").status_checked()?;
|
||||||
} else {
|
} else {
|
||||||
run_type.execute(&nix).arg("upgrade-nix").check_run()?;
|
run_type.execute(&nix).arg("upgrade-nix").status_checked()?;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
run_type.execute(nix_channel).arg("--update").check_run()?;
|
run_type.execute(nix_channel).arg("--update").status_checked()?;
|
||||||
|
|
||||||
if std::path::Path::new(&manifest_json_path).exists() {
|
if std::path::Path::new(&manifest_json_path).exists() {
|
||||||
run_type
|
run_type
|
||||||
@@ -360,9 +380,9 @@ pub fn run_nix(ctx: &ExecutionContext) -> Result<()> {
|
|||||||
.arg("profile")
|
.arg("profile")
|
||||||
.arg("upgrade")
|
.arg("upgrade")
|
||||||
.arg(".*")
|
.arg(".*")
|
||||||
.check_run()
|
.status_checked()
|
||||||
} else {
|
} else {
|
||||||
run_type.execute(&nix_env).arg("--upgrade").check_run()
|
run_type.execute(&nix_env).arg("--upgrade").status_checked()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -371,42 +391,40 @@ pub fn run_yadm(ctx: &ExecutionContext) -> Result<()> {
|
|||||||
|
|
||||||
print_separator("yadm");
|
print_separator("yadm");
|
||||||
|
|
||||||
ctx.run_type().execute(yadm).arg("pull").check_run()
|
ctx.run_type().execute(yadm).arg("pull").status_checked()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn run_asdf(run_type: RunType) -> Result<()> {
|
pub fn run_asdf(run_type: RunType) -> Result<()> {
|
||||||
let asdf = require("asdf")?;
|
let asdf = require("asdf")?;
|
||||||
|
|
||||||
print_separator("asdf");
|
print_separator("asdf");
|
||||||
let exit_status = run_type.execute(&asdf).arg("update").spawn()?.wait()?;
|
run_type.execute(&asdf).arg("update").status_checked_with_codes(&[42])?;
|
||||||
|
|
||||||
if let ExecutorExitStatus::Wet(e) = exit_status {
|
run_type
|
||||||
if !(e.success() || e.code().map(|c| c == 42).unwrap_or(false)) {
|
.execute(&asdf)
|
||||||
return Err(TopgradeError::ProcessFailed(e).into());
|
.args(["plugin", "update", "--all"])
|
||||||
}
|
.status_checked()
|
||||||
}
|
|
||||||
run_type.execute(&asdf).args(["plugin", "update", "--all"]).check_run()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn run_home_manager(run_type: RunType) -> Result<()> {
|
pub fn run_home_manager(run_type: RunType) -> Result<()> {
|
||||||
let home_manager = require("home-manager")?;
|
let home_manager = require("home-manager")?;
|
||||||
|
|
||||||
print_separator("home-manager");
|
print_separator("home-manager");
|
||||||
run_type.execute(home_manager).arg("switch").check_run()
|
run_type.execute(home_manager).arg("switch").status_checked()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn run_tldr(run_type: RunType) -> Result<()> {
|
pub fn run_tldr(run_type: RunType) -> Result<()> {
|
||||||
let tldr = require("tldr")?;
|
let tldr = require("tldr")?;
|
||||||
|
|
||||||
print_separator("TLDR");
|
print_separator("TLDR");
|
||||||
run_type.execute(tldr).arg("--update").check_run()
|
run_type.execute(tldr).arg("--update").status_checked()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn run_pearl(run_type: RunType) -> Result<()> {
|
pub fn run_pearl(run_type: RunType) -> Result<()> {
|
||||||
let pearl = require("pearl")?;
|
let pearl = require("pearl")?;
|
||||||
print_separator("pearl");
|
print_separator("pearl");
|
||||||
|
|
||||||
run_type.execute(pearl).arg("update").check_run()
|
run_type.execute(pearl).arg("update").status_checked()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn run_sdkman(base_dirs: &BaseDirs, cleanup: bool, run_type: RunType) -> Result<()> {
|
pub fn run_sdkman(base_dirs: &BaseDirs, cleanup: bool, run_type: RunType) -> Result<()> {
|
||||||
@@ -440,27 +458,33 @@ pub fn run_sdkman(base_dirs: &BaseDirs, cleanup: bool, run_type: RunType) -> Res
|
|||||||
run_type
|
run_type
|
||||||
.execute(&bash)
|
.execute(&bash)
|
||||||
.args(["-c", cmd_selfupdate.as_str()])
|
.args(["-c", cmd_selfupdate.as_str()])
|
||||||
.check_run()?;
|
.status_checked()?;
|
||||||
}
|
}
|
||||||
|
|
||||||
let cmd_update = format!("source {} && sdk update", &sdkman_init_path);
|
let cmd_update = format!("source {} && sdk update", &sdkman_init_path);
|
||||||
run_type.execute(&bash).args(["-c", cmd_update.as_str()]).check_run()?;
|
run_type
|
||||||
|
.execute(&bash)
|
||||||
|
.args(["-c", cmd_update.as_str()])
|
||||||
|
.status_checked()?;
|
||||||
|
|
||||||
let cmd_upgrade = format!("source {} && sdk upgrade", &sdkman_init_path);
|
let cmd_upgrade = format!("source {} && sdk upgrade", &sdkman_init_path);
|
||||||
run_type.execute(&bash).args(["-c", cmd_upgrade.as_str()]).check_run()?;
|
run_type
|
||||||
|
.execute(&bash)
|
||||||
|
.args(["-c", cmd_upgrade.as_str()])
|
||||||
|
.status_checked()?;
|
||||||
|
|
||||||
if cleanup {
|
if cleanup {
|
||||||
let cmd_flush_archives = format!("source {} && sdk flush archives", &sdkman_init_path);
|
let cmd_flush_archives = format!("source {} && sdk flush archives", &sdkman_init_path);
|
||||||
run_type
|
run_type
|
||||||
.execute(&bash)
|
.execute(&bash)
|
||||||
.args(["-c", cmd_flush_archives.as_str()])
|
.args(["-c", cmd_flush_archives.as_str()])
|
||||||
.check_run()?;
|
.status_checked()?;
|
||||||
|
|
||||||
let cmd_flush_temp = format!("source {} && sdk flush temp", &sdkman_init_path);
|
let cmd_flush_temp = format!("source {} && sdk flush temp", &sdkman_init_path);
|
||||||
run_type
|
run_type
|
||||||
.execute(&bash)
|
.execute(&bash)
|
||||||
.args(["-c", cmd_flush_temp.as_str()])
|
.args(["-c", cmd_flush_temp.as_str()])
|
||||||
.check_run()?;
|
.status_checked()?;
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
@@ -471,7 +495,7 @@ pub fn run_bun(ctx: &ExecutionContext) -> Result<()> {
|
|||||||
|
|
||||||
print_separator("Bun");
|
print_separator("Bun");
|
||||||
|
|
||||||
ctx.run_type().execute(bun).arg("upgrade").check_run()
|
ctx.run_type().execute(bun).arg("upgrade").status_checked()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Update dotfiles with `rcm(7)`.
|
/// Update dotfiles with `rcm(7)`.
|
||||||
@@ -481,10 +505,10 @@ pub fn run_rcm(ctx: &ExecutionContext) -> Result<()> {
|
|||||||
let rcup = require("rcup")?;
|
let rcup = require("rcup")?;
|
||||||
|
|
||||||
print_separator("rcm");
|
print_separator("rcm");
|
||||||
ctx.run_type().execute(rcup).arg("-v").check_run()
|
ctx.run_type().execute(rcup).arg("-v").status_checked()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn reboot() {
|
pub fn reboot() -> Result<()> {
|
||||||
print!("Rebooting...");
|
print!("Rebooting...");
|
||||||
Command::new("sudo").arg("reboot").spawn().unwrap().wait().unwrap();
|
Command::new("sudo").arg("reboot").status_checked()
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,11 +2,12 @@ use std::convert::TryFrom;
|
|||||||
use std::path::Path;
|
use std::path::Path;
|
||||||
use std::{ffi::OsStr, process::Command};
|
use std::{ffi::OsStr, process::Command};
|
||||||
|
|
||||||
use anyhow::Result;
|
use color_eyre::eyre::Result;
|
||||||
use log::debug;
|
use tracing::debug;
|
||||||
|
|
||||||
|
use crate::command::CommandExt;
|
||||||
use crate::execution_context::ExecutionContext;
|
use crate::execution_context::ExecutionContext;
|
||||||
use crate::executor::{CommandExt, RunType};
|
use crate::executor::RunType;
|
||||||
use crate::terminal::{print_separator, print_warning};
|
use crate::terminal::{print_separator, print_warning};
|
||||||
use crate::utils::require;
|
use crate::utils::require;
|
||||||
use crate::{error::SkipStep, steps::git::Repositories};
|
use crate::{error::SkipStep, steps::git::Repositories};
|
||||||
@@ -18,23 +19,22 @@ pub fn run_chocolatey(ctx: &ExecutionContext) -> Result<()> {
|
|||||||
|
|
||||||
print_separator("Chocolatey");
|
print_separator("Chocolatey");
|
||||||
|
|
||||||
let mut cmd = &choco;
|
let mut command = match ctx.sudo() {
|
||||||
let mut args = vec!["upgrade", "all"];
|
Some(sudo) => {
|
||||||
|
let mut command = ctx.run_type().execute(sudo);
|
||||||
|
command.arg(choco);
|
||||||
|
command
|
||||||
|
}
|
||||||
|
None => ctx.run_type().execute(choco),
|
||||||
|
};
|
||||||
|
|
||||||
if let Some(sudo) = ctx.sudo() {
|
command.args(["upgrade", "all"]);
|
||||||
cmd = sudo;
|
|
||||||
args.insert(0, "choco");
|
|
||||||
}
|
|
||||||
|
|
||||||
let mut command = ctx.run_type().execute(cmd);
|
|
||||||
|
|
||||||
command.args(&args);
|
|
||||||
|
|
||||||
if yes {
|
if yes {
|
||||||
command.arg("--yes");
|
command.arg("--yes");
|
||||||
}
|
}
|
||||||
|
|
||||||
command.check_run()
|
command.status_checked()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn run_winget(ctx: &ExecutionContext) -> Result<()> {
|
pub fn run_winget(ctx: &ExecutionContext) -> Result<()> {
|
||||||
@@ -47,7 +47,10 @@ pub fn run_winget(ctx: &ExecutionContext) -> Result<()> {
|
|||||||
return Err(SkipStep(String::from("Winget is disabled by default")).into());
|
return Err(SkipStep(String::from("Winget is disabled by default")).into());
|
||||||
}
|
}
|
||||||
|
|
||||||
ctx.run_type().execute(&winget).args(["upgrade", "--all"]).check_run()
|
ctx.run_type()
|
||||||
|
.execute(&winget)
|
||||||
|
.args(["upgrade", "--all"])
|
||||||
|
.status_checked()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn run_scoop(cleanup: bool, run_type: RunType) -> Result<()> {
|
pub fn run_scoop(cleanup: bool, run_type: RunType) -> Result<()> {
|
||||||
@@ -55,18 +58,18 @@ pub fn run_scoop(cleanup: bool, run_type: RunType) -> Result<()> {
|
|||||||
|
|
||||||
print_separator("Scoop");
|
print_separator("Scoop");
|
||||||
|
|
||||||
run_type.execute(&scoop).args(["update"]).check_run()?;
|
run_type.execute(&scoop).args(["update"]).status_checked()?;
|
||||||
run_type.execute(&scoop).args(["update", "*"]).check_run()?;
|
run_type.execute(&scoop).args(["update", "*"]).status_checked()?;
|
||||||
|
|
||||||
if cleanup {
|
if cleanup {
|
||||||
run_type.execute(&scoop).args(["cleanup", "*"]).check_run()?;
|
run_type.execute(&scoop).args(["cleanup", "*"]).status_checked()?;
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_wsl_distributions(wsl: Path) -> Result<Vec<String>> {
|
fn get_wsl_distributions(wsl: &Path) -> Result<Vec<String>> {
|
||||||
let output = Command::new(wsl).args(["--list", "-q"]).check_output()?;
|
let output = Command::new(wsl).args(["--list", "-q"]).output_checked_utf8()?.stdout;
|
||||||
Ok(output
|
Ok(output
|
||||||
.lines()
|
.lines()
|
||||||
.filter(|s| !s.is_empty())
|
.filter(|s| !s.is_empty())
|
||||||
@@ -77,10 +80,10 @@ fn get_wsl_distributions(wsl: Path) -> Result<Vec<String>> {
|
|||||||
fn upgrade_wsl_distribution(wsl: &Path, dist: &str, ctx: &ExecutionContext) -> Result<()> {
|
fn upgrade_wsl_distribution(wsl: &Path, dist: &str, ctx: &ExecutionContext) -> Result<()> {
|
||||||
let topgrade = Command::new(wsl)
|
let topgrade = Command::new(wsl)
|
||||||
.args(["-d", dist, "bash", "-lc", "which topgrade"])
|
.args(["-d", dist, "bash", "-lc", "which topgrade"])
|
||||||
.check_output()
|
.output_checked_utf8()
|
||||||
.map_err(|_| SkipStep(String::from("Could not find Topgrade installed in WSL")))?;
|
.map_err(|_| SkipStep(String::from("Could not find Topgrade installed in WSL")))?;
|
||||||
|
|
||||||
let mut command = ctx.run_type().execute(&wsl);
|
let mut command = ctx.run_type().execute(wsl);
|
||||||
command
|
command
|
||||||
.args(["-d", dist, "bash", "-c"])
|
.args(["-d", dist, "bash", "-c"])
|
||||||
.arg(format!("TOPGRADE_PREFIX={} exec {}", dist, topgrade));
|
.arg(format!("TOPGRADE_PREFIX={} exec {}", dist, topgrade));
|
||||||
@@ -89,12 +92,12 @@ fn upgrade_wsl_distribution(wsl: &Path, dist: &str, ctx: &ExecutionContext) -> R
|
|||||||
command.arg("-y");
|
command.arg("-y");
|
||||||
}
|
}
|
||||||
|
|
||||||
command.check_run()
|
command.status_checked()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn run_wsl_topgrade(ctx: &ExecutionContext) -> Result<()> {
|
pub fn run_wsl_topgrade(ctx: &ExecutionContext) -> Result<()> {
|
||||||
let wsl = require("wsl")?;
|
let wsl = require("wsl")?;
|
||||||
let wsl_distributions = get_wsl_distributions(wsl)?;
|
let wsl_distributions = get_wsl_distributions(&wsl)?;
|
||||||
let mut ran = false;
|
let mut ran = false;
|
||||||
|
|
||||||
debug!("WSL distributions: {:?}", wsl_distributions);
|
debug!("WSL distributions: {:?}", wsl_distributions);
|
||||||
@@ -129,12 +132,17 @@ pub fn windows_update(ctx: &ExecutionContext) -> Result<()> {
|
|||||||
|
|
||||||
print_separator("Windows Update");
|
print_separator("Windows Update");
|
||||||
println!("Running Windows Update. Check the control panel for progress.");
|
println!("Running Windows Update. Check the control panel for progress.");
|
||||||
ctx.run_type().execute(&usoclient).arg("ScanInstallWait").check_run()?;
|
ctx.run_type()
|
||||||
ctx.run_type().execute(&usoclient).arg("StartInstall").check_run()
|
.execute(&usoclient)
|
||||||
|
.arg("ScanInstallWait")
|
||||||
|
.status_checked()?;
|
||||||
|
ctx.run_type().execute(&usoclient).arg("StartInstall").status_checked()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn reboot() {
|
pub fn reboot() -> Result<()> {
|
||||||
Command::new("shutdown").args(["/R", "/T", "0"]).spawn().ok();
|
// If this works, it won't return, but if it doesn't work, it may return a useful error
|
||||||
|
// message.
|
||||||
|
Command::new("shutdown").args(["/R", "/T", "0"]).status_checked()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn insert_startup_scripts(ctx: &ExecutionContext, git_repos: &mut Repositories) -> Result<()> {
|
pub fn insert_startup_scripts(ctx: &ExecutionContext, git_repos: &mut Repositories) -> Result<()> {
|
||||||
|
|||||||
@@ -3,10 +3,10 @@ use std::path::Path;
|
|||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
use std::process::Command;
|
use std::process::Command;
|
||||||
|
|
||||||
use anyhow::Result;
|
use color_eyre::eyre::Result;
|
||||||
|
|
||||||
|
use crate::command::CommandExt;
|
||||||
use crate::execution_context::ExecutionContext;
|
use crate::execution_context::ExecutionContext;
|
||||||
use crate::executor::CommandExt;
|
|
||||||
use crate::terminal::{is_dumb, print_separator};
|
use crate::terminal::{is_dumb, print_separator};
|
||||||
use crate::utils::{require_option, which, PathExt};
|
use crate::utils::{require_option, which, PathExt};
|
||||||
use crate::Step;
|
use crate::Step;
|
||||||
@@ -27,8 +27,8 @@ impl Powershell {
|
|||||||
let profile = path.as_ref().and_then(|path| {
|
let profile = path.as_ref().and_then(|path| {
|
||||||
Command::new(path)
|
Command::new(path)
|
||||||
.args(["-NoProfile", "-Command", "Split-Path $profile"])
|
.args(["-NoProfile", "-Command", "Split-Path $profile"])
|
||||||
.check_output()
|
.output_checked_utf8()
|
||||||
.map(|output| PathBuf::from(output.trim()))
|
.map(|output| PathBuf::from(output.stdout.trim()))
|
||||||
.and_then(|p| p.require())
|
.and_then(|p| p.require())
|
||||||
.ok()
|
.ok()
|
||||||
});
|
});
|
||||||
@@ -52,8 +52,8 @@ impl Powershell {
|
|||||||
"-Command",
|
"-Command",
|
||||||
&format!("Get-Module -ListAvailable {}", command),
|
&format!("Get-Module -ListAvailable {}", command),
|
||||||
])
|
])
|
||||||
.check_output()
|
.output_checked_utf8()
|
||||||
.map(|result| !result.is_empty())
|
.map(|result| !result.stdout.is_empty())
|
||||||
.unwrap_or(false)
|
.unwrap_or(false)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -81,7 +81,7 @@ impl Powershell {
|
|||||||
.execute(powershell)
|
.execute(powershell)
|
||||||
// This probably doesn't need `shell_words::join`.
|
// This probably doesn't need `shell_words::join`.
|
||||||
.args(["-NoProfile", "-Command", &cmd.join(" ")])
|
.args(["-NoProfile", "-Command", &cmd.join(" ")])
|
||||||
.check_run()
|
.status_checked()
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(windows)]
|
#[cfg(windows)]
|
||||||
@@ -119,6 +119,6 @@ impl Powershell {
|
|||||||
}
|
}
|
||||||
),
|
),
|
||||||
])
|
])
|
||||||
.check_run()
|
.status_checked()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,8 @@
|
|||||||
use anyhow::Result;
|
use color_eyre::eyre::Result;
|
||||||
|
|
||||||
use crate::{error::SkipStep, execution_context::ExecutionContext, terminal::print_separator, utils};
|
use crate::{
|
||||||
|
command::CommandExt, error::SkipStep, execution_context::ExecutionContext, terminal::print_separator, utils,
|
||||||
|
};
|
||||||
|
|
||||||
fn prepare_async_ssh_command(args: &mut Vec<&str>) {
|
fn prepare_async_ssh_command(args: &mut Vec<&str>) {
|
||||||
args.insert(0, "ssh");
|
args.insert(0, "ssh");
|
||||||
@@ -24,7 +26,7 @@ pub fn ssh_step(ctx: &ExecutionContext, hostname: &str) -> Result<()> {
|
|||||||
#[cfg(unix)]
|
#[cfg(unix)]
|
||||||
{
|
{
|
||||||
prepare_async_ssh_command(&mut args);
|
prepare_async_ssh_command(&mut args);
|
||||||
crate::tmux::run_command(ctx, &shell_words::join(args))?;
|
crate::tmux::run_command(ctx, hostname, &shell_words::join(args))?;
|
||||||
Err(SkipStep(String::from("Remote Topgrade launched in Tmux")).into())
|
Err(SkipStep(String::from("Remote Topgrade launched in Tmux")).into())
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -47,6 +49,6 @@ pub fn ssh_step(ctx: &ExecutionContext, hostname: &str) -> Result<()> {
|
|||||||
print_separator(format!("Remote ({})", hostname));
|
print_separator(format!("Remote ({})", hostname));
|
||||||
println!("Connecting to {}...", hostname);
|
println!("Connecting to {}...", hostname);
|
||||||
|
|
||||||
ctx.run_type().execute(ssh).args(&args).check_run()
|
ctx.run_type().execute(ssh).args(&args).status_checked()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,13 +2,13 @@ use std::path::{Path, PathBuf};
|
|||||||
use std::process::Command;
|
use std::process::Command;
|
||||||
use std::{fmt::Display, rc::Rc, str::FromStr};
|
use std::{fmt::Display, rc::Rc, str::FromStr};
|
||||||
|
|
||||||
use anyhow::Result;
|
use color_eyre::eyre::Result;
|
||||||
use log::{debug, error};
|
|
||||||
use regex::Regex;
|
use regex::Regex;
|
||||||
use strum::EnumString;
|
use strum::EnumString;
|
||||||
|
use tracing::{debug, error};
|
||||||
|
|
||||||
|
use crate::command::CommandExt;
|
||||||
use crate::execution_context::ExecutionContext;
|
use crate::execution_context::ExecutionContext;
|
||||||
use crate::executor::CommandExt;
|
|
||||||
use crate::terminal::print_separator;
|
use crate::terminal::print_separator;
|
||||||
use crate::{error::SkipStep, utils, Step};
|
use crate::{error::SkipStep, utils, Step};
|
||||||
|
|
||||||
@@ -61,10 +61,11 @@ impl Vagrant {
|
|||||||
let output = Command::new(&self.path)
|
let output = Command::new(&self.path)
|
||||||
.arg("status")
|
.arg("status")
|
||||||
.current_dir(directory)
|
.current_dir(directory)
|
||||||
.check_output()?;
|
.output_checked_utf8()?;
|
||||||
debug!("Vagrant output in {}: {}", directory, output);
|
debug!("Vagrant output in {}: {}", directory, output);
|
||||||
|
|
||||||
let boxes = output
|
let boxes = output
|
||||||
|
.stdout
|
||||||
.split('\n')
|
.split('\n')
|
||||||
.skip(2)
|
.skip(2)
|
||||||
.take_while(|line| !(line.is_empty() || line.starts_with('\r')))
|
.take_while(|line| !(line.is_empty() || line.starts_with('\r')))
|
||||||
@@ -115,7 +116,7 @@ impl<'a> TemporaryPowerOn<'a> {
|
|||||||
.execute(vagrant)
|
.execute(vagrant)
|
||||||
.args([subcommand, &vagrant_box.name])
|
.args([subcommand, &vagrant_box.name])
|
||||||
.current_dir(vagrant_box.path.clone())
|
.current_dir(vagrant_box.path.clone())
|
||||||
.check_run()?;
|
.status_checked()?;
|
||||||
Ok(TemporaryPowerOn {
|
Ok(TemporaryPowerOn {
|
||||||
vagrant,
|
vagrant,
|
||||||
vagrant_box,
|
vagrant_box,
|
||||||
@@ -142,7 +143,7 @@ impl<'a> Drop for TemporaryPowerOn<'a> {
|
|||||||
.execute(self.vagrant)
|
.execute(self.vagrant)
|
||||||
.args([subcommand, &self.vagrant_box.name])
|
.args([subcommand, &self.vagrant_box.name])
|
||||||
.current_dir(self.vagrant_box.path.clone())
|
.current_dir(self.vagrant_box.path.clone())
|
||||||
.check_run()
|
.status_checked()
|
||||||
.ok();
|
.ok();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -199,7 +200,7 @@ pub fn topgrade_vagrant_box(ctx: &ExecutionContext, vagrant_box: &VagrantBox) ->
|
|||||||
.execute(&vagrant.path)
|
.execute(&vagrant.path)
|
||||||
.current_dir(&vagrant_box.path)
|
.current_dir(&vagrant_box.path)
|
||||||
.args(["ssh", "-c", &command])
|
.args(["ssh", "-c", &command])
|
||||||
.check_run()
|
.status_checked()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn upgrade_vagrant_boxes(ctx: &ExecutionContext) -> Result<()> {
|
pub fn upgrade_vagrant_boxes(ctx: &ExecutionContext) -> Result<()> {
|
||||||
@@ -208,12 +209,12 @@ pub fn upgrade_vagrant_boxes(ctx: &ExecutionContext) -> Result<()> {
|
|||||||
|
|
||||||
let outdated = Command::new(&vagrant)
|
let outdated = Command::new(&vagrant)
|
||||||
.args(["box", "outdated", "--global"])
|
.args(["box", "outdated", "--global"])
|
||||||
.check_output()?;
|
.output_checked_utf8()?;
|
||||||
|
|
||||||
let re = Regex::new(r"\* '(.*?)' for '(.*?)' is outdated").unwrap();
|
let re = Regex::new(r"\* '(.*?)' for '(.*?)' is outdated").unwrap();
|
||||||
|
|
||||||
let mut found = false;
|
let mut found = false;
|
||||||
for ele in re.captures_iter(&outdated) {
|
for ele in re.captures_iter(&outdated.stdout) {
|
||||||
found = true;
|
found = true;
|
||||||
let _ = ctx
|
let _ = ctx
|
||||||
.run_type()
|
.run_type()
|
||||||
@@ -222,13 +223,16 @@ pub fn upgrade_vagrant_boxes(ctx: &ExecutionContext) -> Result<()> {
|
|||||||
.arg(ele.get(1).unwrap().as_str())
|
.arg(ele.get(1).unwrap().as_str())
|
||||||
.arg("--provider")
|
.arg("--provider")
|
||||||
.arg(ele.get(2).unwrap().as_str())
|
.arg(ele.get(2).unwrap().as_str())
|
||||||
.check_run();
|
.status_checked();
|
||||||
}
|
}
|
||||||
|
|
||||||
if !found {
|
if !found {
|
||||||
println!("No outdated boxes")
|
println!("No outdated boxes")
|
||||||
} else {
|
} else {
|
||||||
ctx.run_type().execute(&vagrant).args(["box", "prune"]).check_run()?;
|
ctx.run_type()
|
||||||
|
.execute(&vagrant)
|
||||||
|
.args(["box", "prune"])
|
||||||
|
.status_checked()?;
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
|
|||||||
@@ -1,16 +1,22 @@
|
|||||||
|
use std::env;
|
||||||
|
use std::path::PathBuf;
|
||||||
|
use std::process::Command;
|
||||||
|
|
||||||
|
use color_eyre::eyre::eyre;
|
||||||
|
use color_eyre::eyre::Context;
|
||||||
|
use color_eyre::eyre::Result;
|
||||||
|
use directories::BaseDirs;
|
||||||
|
|
||||||
|
use crate::command::CommandExt;
|
||||||
use crate::executor::RunType;
|
use crate::executor::RunType;
|
||||||
use crate::terminal::print_separator;
|
use crate::terminal::print_separator;
|
||||||
use crate::{
|
use crate::{
|
||||||
execution_context::ExecutionContext,
|
execution_context::ExecutionContext,
|
||||||
utils::{which, Check, PathExt},
|
utils::{which, PathExt},
|
||||||
};
|
};
|
||||||
use anyhow::Result;
|
|
||||||
use directories::BaseDirs;
|
#[cfg(unix)]
|
||||||
use std::env;
|
use std::os::unix::process::CommandExt as _;
|
||||||
use std::io;
|
|
||||||
use std::os::unix::process::CommandExt;
|
|
||||||
use std::path::PathBuf;
|
|
||||||
use std::process::{exit, Command};
|
|
||||||
|
|
||||||
pub fn run_tpm(base_dirs: &BaseDirs, run_type: RunType) -> Result<()> {
|
pub fn run_tpm(base_dirs: &BaseDirs, run_type: RunType) -> Result<()> {
|
||||||
let tpm = base_dirs
|
let tpm = base_dirs
|
||||||
@@ -20,7 +26,7 @@ pub fn run_tpm(base_dirs: &BaseDirs, run_type: RunType) -> Result<()> {
|
|||||||
|
|
||||||
print_separator("tmux plugins");
|
print_separator("tmux plugins");
|
||||||
|
|
||||||
run_type.execute(tpm).arg("all").check_run()
|
run_type.execute(tpm).arg("all").status_checked()
|
||||||
}
|
}
|
||||||
|
|
||||||
struct Tmux {
|
struct Tmux {
|
||||||
@@ -44,73 +50,130 @@ impl Tmux {
|
|||||||
command
|
command
|
||||||
}
|
}
|
||||||
|
|
||||||
fn has_session(&self, session_name: &str) -> Result<bool, io::Error> {
|
fn has_session(&self, session_name: &str) -> Result<bool> {
|
||||||
Ok(self
|
Ok(self
|
||||||
.build()
|
.build()
|
||||||
.args(["has-session", "-t", session_name])
|
.args(["has-session", "-t", session_name])
|
||||||
.output()?
|
.output_checked_with(|_| Ok(()))?
|
||||||
.status
|
.status
|
||||||
.success())
|
.success())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn new_session(&self, session_name: &str) -> Result<bool, io::Error> {
|
/// Create a new tmux session with the given name, running the given command.
|
||||||
Ok(self
|
/// The command is passed to `sh` (see "shell-command arguments are sh(1) commands" in the
|
||||||
|
/// `tmux(1)` man page).
|
||||||
|
fn new_session(&self, session_name: &str, window_name: &str, command: &str) -> Result<()> {
|
||||||
|
let _ = self
|
||||||
.build()
|
.build()
|
||||||
.args(["new-session", "-d", "-s", session_name, "-n", "dummy"])
|
// `-d`: initial size comes from the global `default-size` option (instead
|
||||||
.spawn()?
|
// of passing `-x` and `-y` arguments.
|
||||||
.wait()?
|
// (What do those even do?)
|
||||||
.success())
|
// `-s`: session name
|
||||||
|
// `-n`: window name (always `topgrade`)
|
||||||
|
.args(["new-session", "-d", "-s", session_name, "-n", window_name, command])
|
||||||
|
.output_checked()?;
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn run_in_session(&self, command: &str) -> Result<()> {
|
/// Like [`new_session`] but it appends a digit to the session name (if necessary) to
|
||||||
self.build()
|
/// avoid duplicate session names.
|
||||||
.args(["new-window", "-t", "topgrade", command])
|
///
|
||||||
.spawn()?
|
/// The session name is returned.
|
||||||
.wait()?
|
fn new_unique_session(&self, session_name: &str, window_name: &str, command: &str) -> Result<String> {
|
||||||
.check()?;
|
let mut session = session_name.to_owned();
|
||||||
|
for i in 1.. {
|
||||||
|
if !self
|
||||||
|
.has_session(&session)
|
||||||
|
.context("Error determining if a tmux session exists")?
|
||||||
|
{
|
||||||
|
self.new_session(&session, window_name, command)
|
||||||
|
.context("Error running Topgrade in tmux")?;
|
||||||
|
return Ok(session);
|
||||||
|
}
|
||||||
|
session = format!("{session_name}-{i}");
|
||||||
|
}
|
||||||
|
unreachable!()
|
||||||
|
}
|
||||||
|
|
||||||
Ok(())
|
/// Create a new window in the given tmux session, running the given command.
|
||||||
|
fn new_window(&self, session_name: &str, window_name: &str, command: &str) -> Result<()> {
|
||||||
|
self.build()
|
||||||
|
// `-d`: initial size comes from the global `default-size` option (instead
|
||||||
|
// of passing `-x` and `-y` arguments.
|
||||||
|
// (What do those even do?)
|
||||||
|
// `-s`: session name
|
||||||
|
// `-n`: window name
|
||||||
|
.args([
|
||||||
|
"new-window",
|
||||||
|
"-a",
|
||||||
|
"-t",
|
||||||
|
&format!("{session_name}:{window_name}"),
|
||||||
|
"-n",
|
||||||
|
window_name,
|
||||||
|
command,
|
||||||
|
])
|
||||||
|
.env_remove("TMUX")
|
||||||
|
.status_checked()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn window_indices(&self, session_name: &str) -> Result<Vec<usize>> {
|
||||||
|
self.build()
|
||||||
|
.args(["list-windows", "-F", "#{window_index}", "-t", session_name])
|
||||||
|
.output_checked_utf8()?
|
||||||
|
.stdout
|
||||||
|
.lines()
|
||||||
|
.map(|l| l.parse())
|
||||||
|
.collect::<Result<Vec<usize>, _>>()
|
||||||
|
.context("Failed to compute tmux windows")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn run_in_tmux(args: Vec<String>) -> ! {
|
pub fn run_in_tmux(args: Vec<String>) -> Result<()> {
|
||||||
let command = {
|
let command = {
|
||||||
let mut command = vec![
|
let mut command = vec![
|
||||||
String::from("env"),
|
String::from("env"),
|
||||||
String::from("TOPGRADE_KEEP_END=1"),
|
String::from("TOPGRADE_KEEP_END=1"),
|
||||||
String::from("TOPGRADE_INSIDE_TMUX=1"),
|
String::from("TOPGRADE_INSIDE_TMUX=1"),
|
||||||
];
|
];
|
||||||
|
// TODO: Should we use `topgrade` instead of the first argument here, which may be
|
||||||
|
// a local path?
|
||||||
command.extend(env::args());
|
command.extend(env::args());
|
||||||
shell_words::join(command)
|
shell_words::join(command)
|
||||||
};
|
};
|
||||||
|
|
||||||
let tmux = Tmux::new(args);
|
let tmux = Tmux::new(args);
|
||||||
|
|
||||||
if !tmux.has_session("topgrade").expect("Error detecting a tmux session") {
|
// Find an unused session and run `topgrade` in it with the current command's arguments.
|
||||||
tmux.new_session("topgrade").expect("Error creating a tmux session");
|
let session_name = "topgrade";
|
||||||
}
|
let window_name = "topgrade";
|
||||||
|
let session = tmux.new_unique_session(session_name, window_name, &command)?;
|
||||||
tmux.run_in_session(&command).expect("Error running Topgrade in tmux");
|
|
||||||
tmux.build()
|
|
||||||
.args(["kill-window", "-t", "topgrade:dummy"])
|
|
||||||
.output()
|
|
||||||
.expect("Error killing the dummy tmux window");
|
|
||||||
|
|
||||||
|
// Only attach to the newly-created session if we're not currently in a tmux session.
|
||||||
if env::var("TMUX").is_err() {
|
if env::var("TMUX").is_err() {
|
||||||
let err = tmux.build().args(["attach", "-t", "topgrade"]).exec();
|
let err = tmux.build().args(["attach-session", "-t", &session]).exec();
|
||||||
panic!("{:?}", err);
|
Err(eyre!("{err}")).context("Failed to `execvp(3)` tmux")
|
||||||
} else {
|
} else {
|
||||||
println!("Topgrade launched in a new tmux session");
|
println!("Topgrade launched in a new tmux session");
|
||||||
exit(0);
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn run_command(ctx: &ExecutionContext, command: &str) -> Result<()> {
|
pub fn run_command(ctx: &ExecutionContext, window_name: &str, command: &str) -> Result<()> {
|
||||||
Tmux::new(ctx.config().tmux_arguments()?)
|
let tmux = Tmux::new(ctx.config().tmux_arguments()?);
|
||||||
.build()
|
|
||||||
.args(["new-window", "-a", "-t", "topgrade:1", command])
|
match ctx.get_tmux_session() {
|
||||||
.env_remove("TMUX")
|
Some(session_name) => {
|
||||||
.spawn()?
|
let indices = tmux.window_indices(&session_name)?;
|
||||||
.wait()?
|
let last_window = indices
|
||||||
.check()
|
.iter()
|
||||||
|
.last()
|
||||||
|
.ok_or_else(|| eyre!("tmux session {session_name} has no windows"))?;
|
||||||
|
tmux.new_window(&session_name, &format!("{last_window}"), command)?;
|
||||||
|
}
|
||||||
|
None => {
|
||||||
|
let name = tmux.new_unique_session("topgrade", window_name, command)?;
|
||||||
|
ctx.set_tmux_session(name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,17 +1,20 @@
|
|||||||
use anyhow::Result;
|
use color_eyre::eyre::Result;
|
||||||
|
|
||||||
|
use crate::command::CommandExt;
|
||||||
use crate::config::Step;
|
use crate::config::Step;
|
||||||
use crate::terminal::print_separator;
|
use crate::terminal::print_separator;
|
||||||
use crate::{execution_context::ExecutionContext, utils::require};
|
use crate::{execution_context::ExecutionContext, utils::require};
|
||||||
use log::debug;
|
|
||||||
use std::path::Path;
|
use std::path::Path;
|
||||||
use std::{path::PathBuf, process::Command};
|
use std::{path::PathBuf, process::Command};
|
||||||
|
use tracing::debug;
|
||||||
|
|
||||||
fn list_toolboxes(toolbx: &Path) -> Result<Vec<String>> {
|
fn list_toolboxes(toolbx: &Path) -> Result<Vec<String>> {
|
||||||
let output = Command::new(toolbx).args(["list", "--containers"]).output()?;
|
let output = Command::new(toolbx)
|
||||||
let output_str = String::from_utf8(output.stdout)?;
|
.args(["list", "--containers"])
|
||||||
|
.output_checked_utf8()?;
|
||||||
|
|
||||||
let proc: Vec<String> = output_str
|
let proc: Vec<String> = output
|
||||||
|
.stdout
|
||||||
.lines()
|
.lines()
|
||||||
// Skip the first line since that contains only status information
|
// Skip the first line since that contains only status information
|
||||||
.skip(1)
|
.skip(1)
|
||||||
@@ -54,7 +57,7 @@ pub fn run_toolbx(ctx: &ExecutionContext) -> Result<()> {
|
|||||||
args.push("--yes");
|
args.push("--yes");
|
||||||
}
|
}
|
||||||
|
|
||||||
let _output = ctx.run_type().execute(&toolbx).args(&args).check_run();
|
ctx.run_type().execute(&toolbx).args(&args).status_checked()?;
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
|
|||||||
@@ -38,6 +38,14 @@ if exists(":CocUpdateSync")
|
|||||||
CocUpdateSync
|
CocUpdateSync
|
||||||
endif
|
endif
|
||||||
|
|
||||||
|
" TODO: Should this be after `PackerSync`?
|
||||||
|
" Not sure how to sequence this after Packer without doing something weird
|
||||||
|
" with that `PackerComplete` autocommand.
|
||||||
|
if exists(":TSUpdate")
|
||||||
|
echo "TreeSitter Update"
|
||||||
|
TSUpdate
|
||||||
|
endif
|
||||||
|
|
||||||
if exists(':PackerSync')
|
if exists(':PackerSync')
|
||||||
echo "Packer"
|
echo "Packer"
|
||||||
autocmd User PackerComplete quitall
|
autocmd User PackerComplete quitall
|
||||||
|
|||||||
@@ -1,19 +1,20 @@
|
|||||||
|
use crate::command::CommandExt;
|
||||||
use crate::error::{SkipStep, TopgradeError};
|
use crate::error::{SkipStep, TopgradeError};
|
||||||
use anyhow::Result;
|
use color_eyre::eyre::Result;
|
||||||
|
|
||||||
use crate::executor::{CommandExt, Executor, ExecutorOutput, RunType};
|
use crate::executor::{Executor, ExecutorOutput, RunType};
|
||||||
use crate::terminal::print_separator;
|
use crate::terminal::print_separator;
|
||||||
use crate::{
|
use crate::{
|
||||||
execution_context::ExecutionContext,
|
execution_context::ExecutionContext,
|
||||||
utils::{require, PathExt},
|
utils::{require, PathExt},
|
||||||
};
|
};
|
||||||
use directories::BaseDirs;
|
use directories::BaseDirs;
|
||||||
use log::debug;
|
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
use std::{
|
use std::{
|
||||||
io::{self, Write},
|
io::{self, Write},
|
||||||
process::Command,
|
process::Command,
|
||||||
};
|
};
|
||||||
|
use tracing::debug;
|
||||||
|
|
||||||
const UPGRADE_VIM: &str = include_str!("upgrade.vim");
|
const UPGRADE_VIM: &str = include_str!("upgrade.vim");
|
||||||
|
|
||||||
@@ -63,7 +64,7 @@ fn upgrade(command: &mut Executor, ctx: &ExecutionContext) -> Result<()> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if !status.success() {
|
if !status.success() {
|
||||||
return Err(TopgradeError::ProcessFailed(status).into());
|
return Err(TopgradeError::ProcessFailed(command.get_program(), status).into());
|
||||||
} else {
|
} else {
|
||||||
println!("Plugins upgraded")
|
println!("Plugins upgraded")
|
||||||
}
|
}
|
||||||
@@ -84,22 +85,22 @@ pub fn upgrade_ultimate_vimrc(ctx: &ExecutionContext) -> Result<()> {
|
|||||||
.execute(&git)
|
.execute(&git)
|
||||||
.current_dir(&config_dir)
|
.current_dir(&config_dir)
|
||||||
.args(["reset", "--hard"])
|
.args(["reset", "--hard"])
|
||||||
.check_run()?;
|
.status_checked()?;
|
||||||
ctx.run_type()
|
ctx.run_type()
|
||||||
.execute(&git)
|
.execute(&git)
|
||||||
.current_dir(&config_dir)
|
.current_dir(&config_dir)
|
||||||
.args(["clean", "-d", "--force"])
|
.args(["clean", "-d", "--force"])
|
||||||
.check_run()?;
|
.status_checked()?;
|
||||||
ctx.run_type()
|
ctx.run_type()
|
||||||
.execute(&git)
|
.execute(&git)
|
||||||
.current_dir(&config_dir)
|
.current_dir(&config_dir)
|
||||||
.args(["pull", "--rebase"])
|
.args(["pull", "--rebase"])
|
||||||
.check_run()?;
|
.status_checked()?;
|
||||||
ctx.run_type()
|
ctx.run_type()
|
||||||
.execute(python)
|
.execute(python)
|
||||||
.current_dir(config_dir)
|
.current_dir(config_dir)
|
||||||
.arg(update_plugins)
|
.arg(update_plugins)
|
||||||
.check_run()?;
|
.status_checked()?;
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
@@ -107,8 +108,8 @@ pub fn upgrade_ultimate_vimrc(ctx: &ExecutionContext) -> Result<()> {
|
|||||||
pub fn upgrade_vim(base_dirs: &BaseDirs, ctx: &ExecutionContext) -> Result<()> {
|
pub fn upgrade_vim(base_dirs: &BaseDirs, ctx: &ExecutionContext) -> Result<()> {
|
||||||
let vim = require("vim")?;
|
let vim = require("vim")?;
|
||||||
|
|
||||||
let output = Command::new(&vim).arg("--version").check_output()?;
|
let output = Command::new(&vim).arg("--version").output_checked_utf8()?;
|
||||||
if !output.starts_with("VIM") {
|
if !output.stdout.starts_with("VIM") {
|
||||||
return Err(SkipStep(String::from("vim binary might be actually nvim")).into());
|
return Err(SkipStep(String::from("vim binary might be actually nvim")).into());
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -147,5 +148,5 @@ pub fn run_voom(_base_dirs: &BaseDirs, run_type: RunType) -> Result<()> {
|
|||||||
|
|
||||||
print_separator("voom");
|
print_separator("voom");
|
||||||
|
|
||||||
run_type.execute(voom).arg("update").check_run()
|
run_type.execute(voom).arg("update").status_checked()
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,16 +1,19 @@
|
|||||||
use crate::execution_context::ExecutionContext;
|
|
||||||
use crate::executor::{CommandExt, RunType};
|
|
||||||
use crate::git::Repositories;
|
|
||||||
use crate::terminal::print_separator;
|
|
||||||
use crate::utils::{require, PathExt};
|
|
||||||
use anyhow::Result;
|
|
||||||
use directories::BaseDirs;
|
|
||||||
use log::debug;
|
|
||||||
use std::env;
|
use std::env;
|
||||||
use std::path::{Path, PathBuf};
|
use std::path::{Path, PathBuf};
|
||||||
use std::process::Command;
|
use std::process::Command;
|
||||||
|
|
||||||
|
use color_eyre::eyre::Result;
|
||||||
|
use directories::BaseDirs;
|
||||||
|
use tracing::debug;
|
||||||
use walkdir::WalkDir;
|
use walkdir::WalkDir;
|
||||||
|
|
||||||
|
use crate::command::CommandExt;
|
||||||
|
use crate::execution_context::ExecutionContext;
|
||||||
|
use crate::executor::RunType;
|
||||||
|
use crate::git::Repositories;
|
||||||
|
use crate::terminal::print_separator;
|
||||||
|
use crate::utils::{require, PathExt};
|
||||||
|
|
||||||
pub fn run_zr(base_dirs: &BaseDirs, run_type: RunType) -> Result<()> {
|
pub fn run_zr(base_dirs: &BaseDirs, run_type: RunType) -> Result<()> {
|
||||||
let zsh = require("zsh")?;
|
let zsh = require("zsh")?;
|
||||||
|
|
||||||
@@ -19,7 +22,7 @@ pub fn run_zr(base_dirs: &BaseDirs, run_type: RunType) -> Result<()> {
|
|||||||
print_separator("zr");
|
print_separator("zr");
|
||||||
|
|
||||||
let cmd = format!("source {} && zr --update", zshrc(base_dirs).display());
|
let cmd = format!("source {} && zr --update", zshrc(base_dirs).display());
|
||||||
run_type.execute(zsh).args(["-l", "-c", cmd.as_str()]).check_run()
|
run_type.execute(zsh).args(["-l", "-c", cmd.as_str()]).status_checked()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn zshrc(base_dirs: &BaseDirs) -> PathBuf {
|
pub fn zshrc(base_dirs: &BaseDirs) -> PathBuf {
|
||||||
@@ -34,7 +37,7 @@ pub fn run_antibody(run_type: RunType) -> Result<()> {
|
|||||||
|
|
||||||
print_separator("antibody");
|
print_separator("antibody");
|
||||||
|
|
||||||
run_type.execute(antibody).arg("update").check_run()
|
run_type.execute(antibody).arg("update").status_checked()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn run_antigen(base_dirs: &BaseDirs, run_type: RunType) -> Result<()> {
|
pub fn run_antigen(base_dirs: &BaseDirs, run_type: RunType) -> Result<()> {
|
||||||
@@ -48,7 +51,7 @@ pub fn run_antigen(base_dirs: &BaseDirs, run_type: RunType) -> Result<()> {
|
|||||||
print_separator("antigen");
|
print_separator("antigen");
|
||||||
|
|
||||||
let cmd = format!("source {} && (antigen selfupdate ; antigen update)", zshrc.display());
|
let cmd = format!("source {} && (antigen selfupdate ; antigen update)", zshrc.display());
|
||||||
run_type.execute(zsh).args(["-l", "-c", cmd.as_str()]).check_run()
|
run_type.execute(zsh).args(["-l", "-c", cmd.as_str()]).status_checked()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn run_zgenom(base_dirs: &BaseDirs, run_type: RunType) -> Result<()> {
|
pub fn run_zgenom(base_dirs: &BaseDirs, run_type: RunType) -> Result<()> {
|
||||||
@@ -62,7 +65,7 @@ pub fn run_zgenom(base_dirs: &BaseDirs, run_type: RunType) -> Result<()> {
|
|||||||
print_separator("zgenom");
|
print_separator("zgenom");
|
||||||
|
|
||||||
let cmd = format!("source {} && zgenom selfupdate && zgenom update", zshrc.display());
|
let cmd = format!("source {} && zgenom selfupdate && zgenom update", zshrc.display());
|
||||||
run_type.execute(zsh).args(["-l", "-c", cmd.as_str()]).check_run()
|
run_type.execute(zsh).args(["-l", "-c", cmd.as_str()]).status_checked()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn run_zplug(base_dirs: &BaseDirs, run_type: RunType) -> Result<()> {
|
pub fn run_zplug(base_dirs: &BaseDirs, run_type: RunType) -> Result<()> {
|
||||||
@@ -76,7 +79,10 @@ pub fn run_zplug(base_dirs: &BaseDirs, run_type: RunType) -> Result<()> {
|
|||||||
|
|
||||||
print_separator("zplug");
|
print_separator("zplug");
|
||||||
|
|
||||||
run_type.execute(zsh).args(["-i", "-c", "zplug update"]).check_run()
|
run_type
|
||||||
|
.execute(zsh)
|
||||||
|
.args(["-i", "-c", "zplug update"])
|
||||||
|
.status_checked()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn run_zinit(base_dirs: &BaseDirs, run_type: RunType) -> Result<()> {
|
pub fn run_zinit(base_dirs: &BaseDirs, run_type: RunType) -> Result<()> {
|
||||||
@@ -91,7 +97,7 @@ pub fn run_zinit(base_dirs: &BaseDirs, run_type: RunType) -> Result<()> {
|
|||||||
print_separator("zinit");
|
print_separator("zinit");
|
||||||
|
|
||||||
let cmd = format!("source {} && zinit self-update && zinit update --all", zshrc.display(),);
|
let cmd = format!("source {} && zinit self-update && zinit update --all", zshrc.display(),);
|
||||||
run_type.execute(zsh).args(["-i", "-c", cmd.as_str()]).check_run()
|
run_type.execute(zsh).args(["-i", "-c", cmd.as_str()]).status_checked()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn run_zi(base_dirs: &BaseDirs, run_type: RunType) -> Result<()> {
|
pub fn run_zi(base_dirs: &BaseDirs, run_type: RunType) -> Result<()> {
|
||||||
@@ -103,7 +109,7 @@ pub fn run_zi(base_dirs: &BaseDirs, run_type: RunType) -> Result<()> {
|
|||||||
print_separator("zi");
|
print_separator("zi");
|
||||||
|
|
||||||
let cmd = format!("source {} && zi self-update && zi update --all", zshrc.display(),);
|
let cmd = format!("source {} && zi self-update && zi update --all", zshrc.display(),);
|
||||||
run_type.execute(zsh).args(["-i", "-c", &cmd]).check_run()
|
run_type.execute(zsh).args(["-i", "-c", &cmd]).status_checked()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn run_zim(base_dirs: &BaseDirs, run_type: RunType) -> Result<()> {
|
pub fn run_zim(base_dirs: &BaseDirs, run_type: RunType) -> Result<()> {
|
||||||
@@ -111,8 +117,10 @@ pub fn run_zim(base_dirs: &BaseDirs, run_type: RunType) -> Result<()> {
|
|||||||
env::var("ZIM_HOME")
|
env::var("ZIM_HOME")
|
||||||
.or_else(|_| {
|
.or_else(|_| {
|
||||||
Command::new("zsh")
|
Command::new("zsh")
|
||||||
|
// TODO: Should these be quoted?
|
||||||
.args(["-c", "[[ -n ${ZIM_HOME} ]] && print -n ${ZIM_HOME}"])
|
.args(["-c", "[[ -n ${ZIM_HOME} ]] && print -n ${ZIM_HOME}"])
|
||||||
.check_output()
|
.output_checked_utf8()
|
||||||
|
.map(|o| o.stdout)
|
||||||
})
|
})
|
||||||
.map(PathBuf::from)
|
.map(PathBuf::from)
|
||||||
.unwrap_or_else(|_| base_dirs.home_dir().join(".zim"))
|
.unwrap_or_else(|_| base_dirs.home_dir().join(".zim"))
|
||||||
@@ -123,7 +131,7 @@ pub fn run_zim(base_dirs: &BaseDirs, run_type: RunType) -> Result<()> {
|
|||||||
run_type
|
run_type
|
||||||
.execute(zsh)
|
.execute(zsh)
|
||||||
.args(["-i", "-c", "zimfw upgrade && zimfw update"])
|
.args(["-i", "-c", "zimfw upgrade && zimfw update"])
|
||||||
.check_run()
|
.status_checked()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn run_oh_my_zsh(ctx: &ExecutionContext) -> Result<()> {
|
pub fn run_oh_my_zsh(ctx: &ExecutionContext) -> Result<()> {
|
||||||
@@ -135,8 +143,10 @@ pub fn run_oh_my_zsh(ctx: &ExecutionContext) -> Result<()> {
|
|||||||
let custom_dir = env::var::<_>("ZSH_CUSTOM")
|
let custom_dir = env::var::<_>("ZSH_CUSTOM")
|
||||||
.or_else(|_| {
|
.or_else(|_| {
|
||||||
Command::new("zsh")
|
Command::new("zsh")
|
||||||
|
// TODO: Should these be quoted?
|
||||||
.args(["-c", "test $ZSH_CUSTOM && echo -n $ZSH_CUSTOM"])
|
.args(["-c", "test $ZSH_CUSTOM && echo -n $ZSH_CUSTOM"])
|
||||||
.check_output()
|
.output_checked_utf8()
|
||||||
|
.map(|o| o.stdout)
|
||||||
})
|
})
|
||||||
.map(PathBuf::from)
|
.map(PathBuf::from)
|
||||||
.unwrap_or_else(|e| {
|
.unwrap_or_else(|e| {
|
||||||
@@ -168,5 +178,5 @@ pub fn run_oh_my_zsh(ctx: &ExecutionContext) -> Result<()> {
|
|||||||
.execute("zsh")
|
.execute("zsh")
|
||||||
.env("ZSH", &oh_my_zsh)
|
.env("ZSH", &oh_my_zsh)
|
||||||
.arg(&oh_my_zsh.join("tools/upgrade.sh"))
|
.arg(&oh_my_zsh.join("tools/upgrade.sh"))
|
||||||
.check_run_with_codes(&[80])
|
.status_checked_with_codes(&[80])
|
||||||
}
|
}
|
||||||
|
|||||||
108
src/sudo.rs
Normal file
108
src/sudo.rs
Normal file
@@ -0,0 +1,108 @@
|
|||||||
|
use std::ffi::OsStr;
|
||||||
|
use std::path::Path;
|
||||||
|
use std::path::PathBuf;
|
||||||
|
|
||||||
|
use color_eyre::eyre::Context;
|
||||||
|
use color_eyre::eyre::Result;
|
||||||
|
|
||||||
|
use crate::command::CommandExt;
|
||||||
|
use crate::execution_context::ExecutionContext;
|
||||||
|
use crate::executor::Executor;
|
||||||
|
use crate::terminal::print_separator;
|
||||||
|
use crate::utils::which;
|
||||||
|
|
||||||
|
#[derive(Clone, Debug)]
|
||||||
|
pub struct Sudo {
|
||||||
|
/// The path to the `sudo` binary.
|
||||||
|
path: PathBuf,
|
||||||
|
/// The type of program being used as `sudo`.
|
||||||
|
kind: SudoKind,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Sudo {
|
||||||
|
/// Get the `sudo` binary for this platform.
|
||||||
|
pub fn detect() -> Option<Self> {
|
||||||
|
which("doas")
|
||||||
|
.map(|p| (p, SudoKind::Doas))
|
||||||
|
.or_else(|| which("sudo").map(|p| (p, SudoKind::Sudo)))
|
||||||
|
.or_else(|| which("gsudo").map(|p| (p, SudoKind::Gsudo)))
|
||||||
|
.or_else(|| which("pkexec").map(|p| (p, SudoKind::Pkexec)))
|
||||||
|
.map(|(path, kind)| Self { path, kind })
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Elevate permissions with `sudo`.
|
||||||
|
///
|
||||||
|
/// This helps prevent blocking `sudo` prompts from stopping the run in the middle of a
|
||||||
|
/// step.
|
||||||
|
///
|
||||||
|
/// See: https://github.com/topgrade-rs/topgrade/issues/205
|
||||||
|
pub fn elevate(&self, ctx: &ExecutionContext) -> Result<()> {
|
||||||
|
print_separator("Sudo");
|
||||||
|
let mut cmd = ctx.run_type().execute(self);
|
||||||
|
match self.kind {
|
||||||
|
SudoKind::Doas => {
|
||||||
|
// `doas` doesn't have anything like `sudo -v` to cache credentials,
|
||||||
|
// so we just execute a dummy `echo` command so we have something
|
||||||
|
// unobtrusive to run.
|
||||||
|
// See: https://man.openbsd.org/doas
|
||||||
|
cmd.arg("echo");
|
||||||
|
}
|
||||||
|
SudoKind::Sudo => {
|
||||||
|
// From `man sudo` on macOS:
|
||||||
|
// -v, --validate
|
||||||
|
// Update the user's cached credentials, authenticating the user
|
||||||
|
// if necessary. For the sudoers plugin, this extends the sudo
|
||||||
|
// timeout for another 5 minutes by default, but does not run a
|
||||||
|
// command. Not all security policies support cached credentials.
|
||||||
|
cmd.arg("-v");
|
||||||
|
}
|
||||||
|
SudoKind::Gsudo => {
|
||||||
|
// Shows current user, cache and console status.
|
||||||
|
// See: https://gerardog.github.io/gsudo/docs/usage
|
||||||
|
cmd.arg("status");
|
||||||
|
}
|
||||||
|
SudoKind::Pkexec => {
|
||||||
|
// I don't think this does anything; `pkexec` usually asks for
|
||||||
|
// authentication every time, although it can be configured
|
||||||
|
// differently.
|
||||||
|
//
|
||||||
|
// See the note for `doas` above.
|
||||||
|
//
|
||||||
|
// See: https://linux.die.net/man/1/pkexec
|
||||||
|
cmd.arg("echo");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
cmd.status_checked().wrap_err("Failed to elevate permissions")
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Execute a command with `sudo`.
|
||||||
|
pub fn execute_elevated(&self, ctx: &ExecutionContext, command: &Path, interactive: bool) -> Executor {
|
||||||
|
let mut cmd = ctx.run_type().execute(self);
|
||||||
|
|
||||||
|
if let SudoKind::Sudo = self.kind {
|
||||||
|
cmd.arg("--preserve-env=DIFFPROG");
|
||||||
|
}
|
||||||
|
|
||||||
|
if interactive {
|
||||||
|
cmd.arg("-i");
|
||||||
|
}
|
||||||
|
|
||||||
|
cmd.arg(command);
|
||||||
|
|
||||||
|
cmd
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Copy, Debug)]
|
||||||
|
enum SudoKind {
|
||||||
|
Doas,
|
||||||
|
Sudo,
|
||||||
|
Gsudo,
|
||||||
|
Pkexec,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl AsRef<OsStr> for Sudo {
|
||||||
|
fn as_ref(&self) -> &OsStr {
|
||||||
|
self.path.as_ref()
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -8,14 +8,17 @@ use std::sync::Mutex;
|
|||||||
use std::time::Duration;
|
use std::time::Duration;
|
||||||
|
|
||||||
use chrono::{Local, Timelike};
|
use chrono::{Local, Timelike};
|
||||||
|
use color_eyre::eyre;
|
||||||
|
use color_eyre::eyre::Context;
|
||||||
use console::{style, Key, Term};
|
use console::{style, Key, Term};
|
||||||
use lazy_static::lazy_static;
|
use lazy_static::lazy_static;
|
||||||
use log::{debug, error};
|
|
||||||
#[cfg(target_os = "macos")]
|
#[cfg(target_os = "macos")]
|
||||||
use notify_rust::{Notification, Timeout};
|
use notify_rust::{Notification, Timeout};
|
||||||
|
use tracing::{debug, error};
|
||||||
#[cfg(windows)]
|
#[cfg(windows)]
|
||||||
use which_crate::which;
|
use which_crate::which;
|
||||||
|
|
||||||
|
use crate::command::CommandExt;
|
||||||
use crate::report::StepResult;
|
use crate::report::StepResult;
|
||||||
#[cfg(target_os = "linux")]
|
#[cfg(target_os = "linux")]
|
||||||
use crate::utils::which;
|
use crate::utils::which;
|
||||||
@@ -34,13 +37,8 @@ pub fn shell() -> &'static str {
|
|||||||
which("pwsh").map(|_| "pwsh").unwrap_or("powershell")
|
which("pwsh").map(|_| "pwsh").unwrap_or("powershell")
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn run_shell() {
|
pub fn run_shell() -> eyre::Result<()> {
|
||||||
Command::new(shell())
|
Command::new(shell()).env("IN_TOPGRADE", "1").status_checked()
|
||||||
.env("IN_TOPGRADE", "1")
|
|
||||||
.spawn()
|
|
||||||
.unwrap()
|
|
||||||
.wait()
|
|
||||||
.unwrap();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
struct Terminal {
|
struct Terminal {
|
||||||
@@ -106,7 +104,9 @@ impl Terminal {
|
|||||||
}
|
}
|
||||||
command.args(["-a", "Topgrade", "Topgrade"]);
|
command.args(["-a", "Topgrade", "Topgrade"]);
|
||||||
command.arg(message.as_ref());
|
command.arg(message.as_ref());
|
||||||
command.output().ok();
|
if let Err(err) = command.output_checked() {
|
||||||
|
tracing::error!("{err:?}");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -163,6 +163,19 @@ impl Terminal {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[allow(dead_code)]
|
||||||
|
fn print_error<P: AsRef<str>, Q: AsRef<str>>(&mut self, key: Q, message: P) {
|
||||||
|
let key = key.as_ref();
|
||||||
|
let message = message.as_ref();
|
||||||
|
self.term
|
||||||
|
.write_fmt(format_args!(
|
||||||
|
"{} {}",
|
||||||
|
style(format!("{} failed:", key)).red().bold(),
|
||||||
|
message
|
||||||
|
))
|
||||||
|
.ok();
|
||||||
|
}
|
||||||
|
|
||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
fn print_warning<P: AsRef<str>>(&mut self, message: P) {
|
fn print_warning<P: AsRef<str>>(&mut self, message: P) {
|
||||||
let message = message.as_ref();
|
let message = message.as_ref();
|
||||||
@@ -214,7 +227,7 @@ impl Terminal {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
#[allow(unused_variables)]
|
#[allow(unused_variables)]
|
||||||
fn should_retry(&mut self, interrupted: bool, step_name: &str) -> Result<bool, io::Error> {
|
fn should_retry(&mut self, interrupted: bool, step_name: &str) -> eyre::Result<bool> {
|
||||||
if self.width.is_none() {
|
if self.width.is_none() {
|
||||||
return Ok(false);
|
return Ok(false);
|
||||||
}
|
}
|
||||||
@@ -225,29 +238,31 @@ impl Terminal {
|
|||||||
|
|
||||||
self.notify_desktop(format!("{} failed", step_name), None);
|
self.notify_desktop(format!("{} failed", step_name), None);
|
||||||
|
|
||||||
self.term
|
let prompt_inner = style(format!("{}Retry? (y)es/(N)o/(s)hell/(q)uit", self.prefix))
|
||||||
.write_fmt(format_args!(
|
.yellow()
|
||||||
"\n{}",
|
.bold();
|
||||||
style(format!("{}Retry? (y)es/(N)o/(s)hell/(q)uit", self.prefix))
|
|
||||||
.yellow()
|
self.term.write_fmt(format_args!("\n{}", prompt_inner)).ok();
|
||||||
.bold()
|
|
||||||
))
|
|
||||||
.ok();
|
|
||||||
|
|
||||||
let answer = loop {
|
let answer = loop {
|
||||||
match self.term.read_key() {
|
match self.term.read_key() {
|
||||||
Ok(Key::Char('y')) | Ok(Key::Char('Y')) => break Ok(true),
|
Ok(Key::Char('y')) | Ok(Key::Char('Y')) => break Ok(true),
|
||||||
Ok(Key::Char('s')) | Ok(Key::Char('S')) => {
|
Ok(Key::Char('s')) | Ok(Key::Char('S')) => {
|
||||||
println!("\n\nDropping you to shell. Fix what you need and then exit the shell.\n");
|
println!("\n\nDropping you to shell. Fix what you need and then exit the shell.\n");
|
||||||
run_shell();
|
if let Err(err) = run_shell().context("Failed to run shell") {
|
||||||
break Ok(true);
|
self.term.write_fmt(format_args!("{err:?}\n{}", prompt_inner)).ok();
|
||||||
|
} else {
|
||||||
|
break Ok(true);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
Ok(Key::Char('n')) | Ok(Key::Char('N')) | Ok(Key::Enter) => break Ok(false),
|
Ok(Key::Char('n')) | Ok(Key::Char('N')) | Ok(Key::Enter) => break Ok(false),
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
error!("Error reading from terminal: {}", e);
|
error!("Error reading from terminal: {}", e);
|
||||||
break Ok(false);
|
break Ok(false);
|
||||||
}
|
}
|
||||||
Ok(Key::Char('q')) | Ok(Key::Char('Q')) => return Err(io::Error::from(io::ErrorKind::Interrupted)),
|
Ok(Key::Char('q')) | Ok(Key::Char('Q')) => {
|
||||||
|
return Err(io::Error::from(io::ErrorKind::Interrupted)).context("Quit from user input")
|
||||||
|
}
|
||||||
_ => (),
|
_ => (),
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@@ -268,7 +283,7 @@ impl Default for Terminal {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn should_retry(interrupted: bool, step_name: &str) -> Result<bool, io::Error> {
|
pub fn should_retry(interrupted: bool, step_name: &str) -> eyre::Result<bool> {
|
||||||
TERMINAL.lock().unwrap().should_retry(interrupted, step_name)
|
TERMINAL.lock().unwrap().should_retry(interrupted, step_name)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -276,6 +291,11 @@ pub fn print_separator<P: AsRef<str>>(message: P) {
|
|||||||
TERMINAL.lock().unwrap().print_separator(message)
|
TERMINAL.lock().unwrap().print_separator(message)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[allow(dead_code)]
|
||||||
|
pub fn print_error<P: AsRef<str>, Q: AsRef<str>>(key: Q, message: P) {
|
||||||
|
TERMINAL.lock().unwrap().print_error(key, message)
|
||||||
|
}
|
||||||
|
|
||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
pub fn print_warning<P: AsRef<str>>(message: P) {
|
pub fn print_warning<P: AsRef<str>>(message: P) {
|
||||||
TERMINAL.lock().unwrap().print_warning(message)
|
TERMINAL.lock().unwrap().print_warning(message)
|
||||||
|
|||||||
100
src/utils.rs
100
src/utils.rs
@@ -1,46 +1,11 @@
|
|||||||
use crate::error::{SkipStep, TopgradeError};
|
use crate::error::SkipStep;
|
||||||
use anyhow::Result;
|
use color_eyre::eyre::Result;
|
||||||
|
|
||||||
use log::{debug, error};
|
|
||||||
use std::env;
|
use std::env;
|
||||||
use std::ffi::OsStr;
|
use std::ffi::OsStr;
|
||||||
use std::fmt::Debug;
|
use std::fmt::Debug;
|
||||||
use std::path::{Path, PathBuf};
|
use std::path::{Path, PathBuf};
|
||||||
use std::process::{ExitStatus, Output};
|
use tracing::{debug, error};
|
||||||
|
|
||||||
pub trait Check {
|
|
||||||
fn check(self) -> Result<()>;
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Check for Output {
|
|
||||||
fn check(self) -> Result<()> {
|
|
||||||
self.status.check()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub trait CheckWithCodes {
|
|
||||||
fn check_with_codes(self, codes: &[i32]) -> Result<()>;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Anything that implements CheckWithCodes also implements check
|
|
||||||
// if check_with_codes is given an empty array of codes to check
|
|
||||||
impl<T: CheckWithCodes> Check for T {
|
|
||||||
fn check(self) -> Result<()> {
|
|
||||||
self.check_with_codes(&[])
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl CheckWithCodes for ExitStatus {
|
|
||||||
fn check_with_codes(self, codes: &[i32]) -> Result<()> {
|
|
||||||
// Set the default to be -1 because the option represents a signal termination
|
|
||||||
let code = self.code().unwrap_or(-1);
|
|
||||||
if self.success() || codes.contains(&code) {
|
|
||||||
Ok(())
|
|
||||||
} else {
|
|
||||||
Err(TopgradeError::ProcessFailed(self).into())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub trait PathExt
|
pub trait PathExt
|
||||||
where
|
where
|
||||||
@@ -102,13 +67,6 @@ pub fn which<T: AsRef<OsStr> + Debug>(binary_name: T) -> Option<PathBuf> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn sudo() -> Option<PathBuf> {
|
|
||||||
which("doas")
|
|
||||||
.or_else(|| which("sudo"))
|
|
||||||
.or_else(|| which("gsudo"))
|
|
||||||
.or_else(|| which("pkexec"))
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn editor() -> Vec<String> {
|
pub fn editor() -> Vec<String> {
|
||||||
env::var("EDITOR")
|
env::var("EDITOR")
|
||||||
.unwrap_or_else(|_| String::from(if cfg!(windows) { "notepad" } else { "vi" }))
|
.unwrap_or_else(|_| String::from(if cfg!(windows) { "notepad" } else { "vi" }))
|
||||||
@@ -142,3 +100,55 @@ pub fn require_option<T>(option: Option<T>, cause: String) -> Result<T> {
|
|||||||
Err(SkipStep(cause).into())
|
Err(SkipStep(cause).into())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* sys-info-rs
|
||||||
|
*
|
||||||
|
* Copyright (c) 2015 Siyu Wang
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
|
* in the Software without restriction, including without limitation the rights
|
||||||
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
* copies of the Software, and to permit persons to whom the Software is
|
||||||
|
* furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in all
|
||||||
|
* copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
* SOFTWARE.
|
||||||
|
*/
|
||||||
|
#[cfg(target_family = "unix")]
|
||||||
|
pub fn hostname() -> Result<String> {
|
||||||
|
use std::ffi;
|
||||||
|
extern crate libc;
|
||||||
|
|
||||||
|
unsafe {
|
||||||
|
let buf_size = libc::sysconf(libc::_SC_HOST_NAME_MAX) as usize;
|
||||||
|
let mut buf = Vec::<u8>::with_capacity(buf_size + 1);
|
||||||
|
|
||||||
|
if libc::gethostname(buf.as_mut_ptr() as *mut libc::c_char, buf_size) < 0 {
|
||||||
|
return Err(SkipStep(format!("Failed to get hostname: {}", std::io::Error::last_os_error())).into());
|
||||||
|
}
|
||||||
|
let hostname_len = libc::strnlen(buf.as_ptr() as *const libc::c_char, buf_size);
|
||||||
|
buf.set_len(hostname_len);
|
||||||
|
|
||||||
|
Ok(ffi::CString::new(buf).unwrap().into_string().unwrap())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(target_family = "windows")]
|
||||||
|
pub fn hostname() -> Result<String> {
|
||||||
|
use crate::command::CommandExt;
|
||||||
|
use std::process::Command;
|
||||||
|
|
||||||
|
Command::new("hostname")
|
||||||
|
.output_checked_utf8()
|
||||||
|
.map_err(|err| SkipStep(format!("Failed to get hostname: {}", err)).into())
|
||||||
|
.map(|output| output.stdout.trim().to_owned())
|
||||||
|
}
|
||||||
|
|||||||
80
topgrade.8
80
topgrade.8
@@ -1,80 +0,0 @@
|
|||||||
.hy
|
|
||||||
.TH "topgrade" "8"
|
|
||||||
.SH NAME
|
|
||||||
.PP
|
|
||||||
Topgrade \- Upgrade everything
|
|
||||||
.SH SYNOPSIS
|
|
||||||
.PP
|
|
||||||
topgrade [\fIoptions\f[]]
|
|
||||||
.SH DESCRIPTION
|
|
||||||
.PP
|
|
||||||
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, \fBTopgrade\fR detects which tools you use and runs the appropriate commands to update them.
|
|
||||||
.SH OPTIONS
|
|
||||||
.TP
|
|
||||||
.B \-\-only <only>
|
|
||||||
Run only specific steps
|
|
||||||
.RS
|
|
||||||
.RE
|
|
||||||
.TP
|
|
||||||
.B \-\-disable <disable>
|
|
||||||
Disable specific steps
|
|
||||||
.RS
|
|
||||||
.RE
|
|
||||||
.TP
|
|
||||||
.B \-c, \-\-cleanup
|
|
||||||
Cleanup temporary or old files
|
|
||||||
.RS
|
|
||||||
.RE
|
|
||||||
.TP
|
|
||||||
.B \-n, \-\-dry\-run
|
|
||||||
List the commands that would be run
|
|
||||||
.RS
|
|
||||||
.RE
|
|
||||||
.TP
|
|
||||||
.B \-\-edit\-config
|
|
||||||
Edit the configuration file
|
|
||||||
.RS
|
|
||||||
.RE
|
|
||||||
.TP
|
|
||||||
.B \-h, \-\-help
|
|
||||||
Print help information
|
|
||||||
.RS
|
|
||||||
.RE
|
|
||||||
.TP
|
|
||||||
.B \-k, \-\-keep
|
|
||||||
Prompt for a key before exiting
|
|
||||||
.RS
|
|
||||||
.RE
|
|
||||||
.TP
|
|
||||||
.B \-\-no\-retry
|
|
||||||
Do not ask to retry failed steps
|
|
||||||
.RS
|
|
||||||
.RE
|
|
||||||
.TP
|
|
||||||
.B \-t, \-\-tmux
|
|
||||||
Run inside tmux
|
|
||||||
.RS
|
|
||||||
.RE
|
|
||||||
.TP
|
|
||||||
.B \-V, \-\-version
|
|
||||||
Print version information
|
|
||||||
.RS
|
|
||||||
.RE
|
|
||||||
.TP
|
|
||||||
.B \-v, \-\-verbose
|
|
||||||
Output logs
|
|
||||||
.RS
|
|
||||||
.RE
|
|
||||||
.B \-y, \-\-yes
|
|
||||||
Skip package manager's prompts (experimental)
|
|
||||||
.SH ARGUMENT FORMAT
|
|
||||||
Options can be given in any order.
|
|
||||||
A list of steps must be provided as a list of separate arguments, i.e. 'topgrade --only system shell'.
|
|
||||||
.SH BUGS
|
|
||||||
For a list of bugs see <\fIhttps://github.com/r-darwish/topgrade/issues\fR>.
|
|
||||||
.SH AUTHOR
|
|
||||||
\fBTopgrade\fR is maintained by Roey Dror (\[aq]r\-darwish\[aq]) and many other contributors.
|
|
||||||
You can view the full list at
|
|
||||||
<\fIhttps://github.com/r-darwish/topgrade/graphs/contributors\fR>
|
|
||||||
Reference in New Issue
Block a user