Compare commits

..

2 Commits

Author SHA1 Message Date
Thomas Schönauer
6232f5ebca CD pipeline cleanup (#116)
* Update README.md

* Update release-cross.yml

* Update release.yml

* style(self_update): Run cargo fmt (#108)

The commit 9105a8aac is not formatted, which breaks the CI check.

Co-authored-by: Thomas Schönauer <37108907+DottoDev@users.noreply.github.com>

* Cleanup CI/CD pipeline (#115)

Co-authored-by: pan93412 <pan93412@gmail.com>
2022-11-02 16:29:23 +00:00
Thomas Schönauer
b2b35dcad2 Revert clap version bump (#111)
* Update README.md

* Update release-cross.yml

* Update release.yml

* style(self_update): Run cargo fmt (#108)

The commit 9105a8aac is not formatted, which breaks the CI check.

Co-authored-by: Thomas Schönauer <37108907+DottoDev@users.noreply.github.com>

* Clap dependencie change

* Revert clap changes

Co-authored-by: pan93412 <pan93412@gmail.com>
2022-11-02 15:28:47 +00:00
27 changed files with 193 additions and 453 deletions

View File

@@ -1,5 +0,0 @@
blank_issues_enabled: false
contact_links:
- name: GitHub Discussions
url: https://github.com/topgrade-rs/topgrade/discussions
about: Please ask and answer questions here.

View File

@@ -10,10 +10,7 @@ name: Check and Lint
jobs: jobs:
check: check:
name: Check name: Check
strategy: runs-on: ubuntu-latest
matrix:
platform: [ ubuntu-latest, macos-latest, windows-latest ]
runs-on: ${{ matrix.platform }}
steps: steps:
- uses: actions/checkout@v2 - uses: actions/checkout@v2
- uses: actions-rs/toolchain@v1 - uses: actions-rs/toolchain@v1
@@ -27,10 +24,7 @@ jobs:
fmt: fmt:
name: Rustfmt name: Rustfmt
strategy: runs-on: ubuntu-latest
matrix:
platform: [ ubuntu-latest, macos-latest, windows-latest ]
runs-on: ${{ matrix.platform }}
steps: steps:
- uses: actions/checkout@v2 - uses: actions/checkout@v2
- uses: actions-rs/toolchain@v1 - uses: actions-rs/toolchain@v1
@@ -46,10 +40,7 @@ jobs:
clippy: clippy:
name: Clippy name: Clippy
strategy: runs-on: ubuntu-latest
matrix:
platform: [ ubuntu-latest, macos-latest, windows-latest ]
runs-on: ${{ matrix.platform }}
steps: steps:
- uses: actions/checkout@v2 - uses: actions/checkout@v2
- uses: actions-rs/toolchain@v1 - uses: actions-rs/toolchain@v1
@@ -57,13 +48,8 @@ jobs:
toolchain: stable toolchain: stable
components: clippy components: clippy
override: true override: true
- uses: actions-rs/cargo@v1.0.1 - uses: actions-rs/clippy-check@v1
with: with:
command: clippy token: ${{ secrets.GITHUB_TOKEN }}
args: --all-targets --locked -- -D warnings args: --all-features
name: Clippy Output name: Clippy Output
- uses: actions-rs/cargo@v1.0.1
with:
command: clippy
args: --all-targets --locked --all-features -- -D warnings
name: Clippy (All features) Output

View File

@@ -15,7 +15,7 @@ jobs:
- uses: actions/checkout@v2 - uses: actions/checkout@v2
- uses: actions-rs/toolchain@v1 - uses: actions-rs/toolchain@v1
with: with:
toolchain: stable toolchain: nightly-2022-08-03
override: true override: true
publish: publish:

View File

@@ -19,7 +19,7 @@ jobs:
- uses: actions/checkout@v2 - uses: actions/checkout@v2
- uses: actions-rs/toolchain@v1 - uses: actions-rs/toolchain@v1
with: with:
toolchain: stable toolchain: 1.57.0
profile: minimal profile: minimal
default: true default: true
override: true override: true

View File

@@ -19,7 +19,7 @@ jobs:
- uses: actions/checkout@v2 - uses: actions/checkout@v2
- uses: actions-rs/toolchain@v1 - uses: actions-rs/toolchain@v1
with: with:
toolchain: stable toolchain: 1.57.0
profile: minimal profile: minimal
override: true override: true
components: rustfmt, clippy components: rustfmt, clippy

View File

@@ -1,128 +0,0 @@
# 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.

75
Cargo.lock generated
View File

@@ -225,16 +225,16 @@ dependencies = [
[[package]] [[package]]
name = "clap" name = "clap"
version = "3.1.18" version = "3.2.22"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d2dbdf4bdacb33466e854ce889eee8dfd5729abf7ccd7664d0a2d60cd384440b" checksum = "86447ad904c7fb335a790c9d7fe3d0d971dc523b8ccd1561a520de9a85302750"
dependencies = [ dependencies = [
"atty", "atty",
"bitflags", "bitflags",
"clap_derive", "clap_derive",
"clap_lex", "clap_lex",
"indexmap", "indexmap",
"lazy_static", "once_cell",
"strsim", "strsim",
"termcolor", "termcolor",
"textwrap", "textwrap",
@@ -242,9 +242,9 @@ dependencies = [
[[package]] [[package]]
name = "clap_derive" name = "clap_derive"
version = "3.1.18" version = "3.2.18"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "25320346e922cffe59c0bbc5410c8d8784509efb321488971081313cb1e1a33c" checksum = "ea0c8bce528c4be4da13ea6fead8965e95b6073585a2f05204bd8f4119f82a65"
dependencies = [ dependencies = [
"heck 0.4.0", "heck 0.4.0",
"proc-macro-error", "proc-macro-error",
@@ -660,9 +660,9 @@ checksum = "9b919933a397b79c37e33b77bb2aa3dc8eb6e165ad809e58ff75bc7db2e34574"
[[package]] [[package]]
name = "h2" name = "h2"
version = "0.3.12" version = "0.3.15"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "62eeb471aa3e3c9197aa4bfeabfe02982f6dc96f750486c0bb0009ac58b26d2b" checksum = "5f9f29bc9dda355256b2916cf526ab02ce0aeaaaf2bad60d65ef3f12f11dd0f4"
dependencies = [ dependencies = [
"bytes", "bytes",
"fnv", "fnv",
@@ -985,24 +985,14 @@ dependencies = [
[[package]] [[package]]
name = "mio" name = "mio"
version = "0.7.14" version = "0.8.5"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8067b404fe97c70829f082dec8bcf4f71225d7eaea1d8645349cb76fa06205cc" checksum = "e5d732bc30207a6423068df043e3d02e0735b155ad7ce1a6f76fe2baa5b158de"
dependencies = [ dependencies = [
"libc", "libc",
"log", "log",
"miow", "wasi 0.11.0+wasi-snapshot-preview1",
"ntapi", "windows-sys",
"winapi",
]
[[package]]
name = "miow"
version = "0.3.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b9f1c5b025cda876f66ef43a113f91ebc9f4ccef34843000e0adf6ebbab84e21"
dependencies = [
"winapi",
] ]
[[package]] [[package]]
@@ -1044,15 +1034,6 @@ dependencies = [
"zvariant_derive", "zvariant_derive",
] ]
[[package]]
name = "ntapi"
version = "0.3.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c28774a7fd2fbb4f0babd8237ce554b73af68021b5f695a3cebd6c59bac0980f"
dependencies = [
"winapi",
]
[[package]] [[package]]
name = "num-integer" name = "num-integer"
version = "0.1.45" version = "0.1.45"
@@ -1377,9 +1358,9 @@ dependencies = [
[[package]] [[package]]
name = "regex" name = "regex"
version = "1.5.6" version = "1.6.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d83f127d94bdbcda4c8cc2e50f6f84f4b611f69c902699ca385a39c3a75f9ff1" checksum = "4c4eb3267174b8c6c2f654116623910a0fef09c4753f8dd83db29c48a0df988b"
dependencies = [ dependencies = [
"aho-corasick", "aho-corasick",
"memchr", "memchr",
@@ -1625,12 +1606,6 @@ 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 = "shell-words"
version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "24188a676b6ae68c3b2cb3a01be17fbf7240ce009799bb56d5b1409051e78fde"
[[package]] [[package]]
name = "shellexpand" name = "shellexpand"
version = "2.1.2" version = "2.1.2"
@@ -1780,13 +1755,13 @@ dependencies = [
[[package]] [[package]]
name = "tempfile" name = "tempfile"
version = "3.2.0" version = "3.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dac1c663cfc93810f88aed9b8941d48cabf856a1b111c29a40439018d870eb22" checksum = "5cdb1ef4eaeeaddc8fbd371e5017057064af0911902ef36b39801f67cc6d79e4"
dependencies = [ dependencies = [
"cfg-if", "cfg-if",
"fastrand",
"libc", "libc",
"rand",
"redox_syscall", "redox_syscall",
"remove_dir_all", "remove_dir_all",
"winapi", "winapi",
@@ -1894,9 +1869,9 @@ checksum = "cda74da7e1a664f795bb1f8a87ec406fb89a02522cf6e50620d016add6dbbf5c"
[[package]] [[package]]
name = "tokio" name = "tokio"
version = "1.5.1" version = "1.21.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cd3b82e6e823a9ee7d7f64b08f8ac3d5f08ac988f23157194bd32af3f2f92767" checksum = "a9e03c497dc955702ba729190dc4aac6f2a0ce97f913e5b1b5912fc5039d9099"
dependencies = [ dependencies = [
"autocfg", "autocfg",
"bytes", "bytes",
@@ -1904,9 +1879,9 @@ dependencies = [
"memchr", "memchr",
"mio", "mio",
"num_cpus", "num_cpus",
"once_cell",
"pin-project-lite", "pin-project-lite",
"signal-hook-registry", "signal-hook-registry",
"socket2",
"winapi", "winapi",
] ]
@@ -1923,16 +1898,16 @@ dependencies = [
[[package]] [[package]]
name = "tokio-util" name = "tokio-util"
version = "0.6.9" version = "0.7.4"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9e99e1983e5d376cd8eb4b66604d2e99e79f5bd988c3055891dcd8c9e2604cc0" checksum = "0bb2e075f03b3d66d8d8785356224ba688d2906a371015e225beeb65ca92c740"
dependencies = [ dependencies = [
"bytes", "bytes",
"futures-core", "futures-core",
"futures-sink", "futures-sink",
"log",
"pin-project-lite", "pin-project-lite",
"tokio", "tokio",
"tracing",
] ]
[[package]] [[package]]
@@ -1968,7 +1943,6 @@ dependencies = [
"self_update", "self_update",
"semver", "semver",
"serde", "serde",
"shell-words",
"shellexpand", "shellexpand",
"strum 0.24.1", "strum 0.24.1",
"sys-info", "sys-info",
@@ -2236,12 +2210,13 @@ dependencies = [
[[package]] [[package]]
name = "which" name = "which"
version = "4.1.0" version = "4.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b55551e42cbdf2ce2bedd2203d0cc08dba002c27510f86dab6d0ce304cba3dfe" checksum = "1c831fbbee9e129a8cf93e7747a82da9d95ba8e16621cae60ec2cdc849bacb7b"
dependencies = [ dependencies = [
"either", "either",
"libc", "libc",
"once_cell",
] ]
[[package]] [[package]]

View File

@@ -20,44 +20,43 @@ path = "src/main.rs"
##name = "topgrade_lib" ##name = "topgrade_lib"
[dependencies] [dependencies]
home = "~0.5" home = "0.5"
directories = "~4.0" directories = "4.0"
serde = { version = "~1.0", features = ["derive"] } serde = { version = "1.0", features = ["derive"] }
toml = "0.5" 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" log = "0.4"
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" 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" 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" sys-info = "0.9"
semver = "~1.0" semver = "1.0"
shell-words = "~1.1"
[target.'cfg(target_os = "macos")'.dependencies] [target.'cfg(target_os = "macos")'.dependencies]
notify-rust = "~4.5" notify-rust = "4.5"
[target.'cfg(unix)'.dependencies] [target.'cfg(unix)'.dependencies]
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"] }
[target.'cfg(windows)'.dependencies] [target.'cfg(windows)'.dependencies]
self_update_crate = { version = "~0.30", default-features = false, optional = true, package = "self_update", features = ["archive-zip", "compression-zip-deflate", "rustls"] } self_update_crate = { version = "0.30", default-features = false, optional = true, package = "self_update", features = ["archive-zip", "compression-zip-deflate", "rustls"] }
winapi = "~0.3" winapi = "0.3"
parselnk = "~0.1" parselnk = "0.1"
[profile.release] [profile.release]
lto = true lto = true

View File

@@ -41,7 +41,7 @@ You can visit the documentation at [topgrade-rs.github.io](https://topgrade-rs.g
## Usage ## Usage
Just run `topgrade`. Just run `topgrade`.
See [the documentation](https://topgrade-rs.github.io/) for the list of things Topgrade supports. See [the wiki](https://github.com/r-darwish/topgrade/wiki/Step-list) for the list of things Topgrade supports.
## Customization ## Customization
@@ -84,6 +84,6 @@ To limit the execution only to specific hosts use the `--remote-host-limit` para
## ToDo ## 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.
- [ ] Split up code into more maintainable parts, eg. putting every linux package manager in a own submodule of linux.rs. - Split up code into more maintainable parts, eg. putting every linux package manager in a own submodule of linux.rs.

View File

@@ -1,16 +1,16 @@
#![allow(dead_code)] #![allow(dead_code)]
use anyhow::Context; use std::collections::BTreeMap;
use std::fs::write;
use std::path::PathBuf;
use std::process::Command;
use std::{env, fs};
use anyhow::Result; use anyhow::Result;
use clap::{ArgEnum, Parser}; use clap::{ArgEnum, Parser};
use directories::BaseDirs; use directories::BaseDirs;
use log::debug; use log::debug;
use regex::Regex; use regex::Regex;
use serde::Deserialize; use serde::Deserialize;
use std::collections::BTreeMap;
use std::fs::write;
use std::path::PathBuf;
use std::process::Command;
use std::{env, fs};
use strum::{EnumIter, EnumString, EnumVariantNames, IntoEnumIterator}; use strum::{EnumIter, EnumString, EnumVariantNames, IntoEnumIterator};
use sys_info::hostname; use sys_info::hostname;
use which_crate::which; use which_crate::which;
@@ -626,16 +626,8 @@ impl Config {
} }
/// Extra Tmux arguments /// Extra Tmux arguments
pub fn tmux_arguments(&self) -> anyhow::Result<Vec<String>> { pub fn tmux_arguments(&self) -> &Option<String> {
let args = &self.config_file.tmux_arguments.as_deref().unwrap_or_default(); &self.config_file.tmux_arguments
shell_words::split(args)
// The only time the parse failed is in case of a missing close quote.
// The error message looks like this:
// Error: Failed to parse `tmux_arguments`: `'foo`
//
// Caused by:
// missing closing quote
.with_context(|| format!("Failed to parse `tmux_arguments`: `{args}`"))
} }
/// Prompt for a key before exiting /// Prompt for a key before exiting

View File

@@ -1,7 +1,10 @@
use lazy_static::lazy_static;
use std::sync::atomic::{AtomicBool, Ordering}; use std::sync::atomic::{AtomicBool, Ordering};
/// A global variable telling whether the application has been interrupted. lazy_static! {
static INTERRUPTED: AtomicBool = AtomicBool::new(false); /// A global variable telling whether the application has been interrupted.
static ref INTERRUPTED: AtomicBool = AtomicBool::new(false);
}
/// Tells whether the program has been interrupted /// Tells whether the program has been interrupted
pub fn interrupted() -> bool { pub fn interrupted() -> bool {

View File

@@ -194,12 +194,11 @@ impl DryCommand {
print!( print!(
"Dry running: {} {}", "Dry running: {} {}",
self.program.to_string_lossy(), self.program.to_string_lossy(),
shell_words::join( self.args
self.args .iter()
.iter() .map(|a| String::from(a.to_string_lossy()))
.map(|a| String::from(a.to_string_lossy())) .collect::<Vec<String>>()
.collect::<Vec<String>>() .join(" ")
)
); );
match &self.directory { match &self.directory {
Some(dir) => println!(" in {}", dir.to_string_lossy()), Some(dir) => println!(" in {}", dir.to_string_lossy()),

View File

@@ -79,7 +79,7 @@ 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());
} }
} }
@@ -351,7 +351,6 @@ fn run() -> Result<()> {
runner.execute(Step::Kakoune, "Kakoune", || kakoune::upgrade_kak_plug(&ctx))?; runner.execute(Step::Kakoune, "Kakoune", || kakoune::upgrade_kak_plug(&ctx))?;
runner.execute(Step::Node, "npm", || node::run_npm_upgrade(&ctx))?; runner.execute(Step::Node, "npm", || node::run_npm_upgrade(&ctx))?;
runner.execute(Step::Node, "yarn", || node::run_yarn_upgrade(&ctx))?; runner.execute(Step::Node, "yarn", || node::run_yarn_upgrade(&ctx))?;
runner.execute(Step::Node, "pnpm", || node::run_pnpm_upgrade(&ctx))?;
runner.execute(Step::Containers, "Containers", || containers::run_containers(&ctx))?; runner.execute(Step::Containers, "Containers", || containers::run_containers(&ctx))?;
runner.execute(Step::Deno, "deno", || node::deno_upgrade(&ctx))?; runner.execute(Step::Deno, "deno", || node::deno_upgrade(&ctx))?;
runner.execute(Step::Composer, "composer", || generic::run_composer_update(&ctx))?; runner.execute(Step::Composer, "composer", || generic::run_composer_update(&ctx))?;
@@ -524,10 +523,7 @@ fn main() {
.is_some()); .is_some());
if !skip_print { if !skip_print {
// The `Debug` implementation of `anyhow::Result` prints a multi-line println!("Error: {}", error);
// error message that includes all the 'causes' added with
// `.with_context(...)` calls.
println!("Error: {:?}", error);
} }
exit(1); exit(1);
} }

View File

@@ -87,7 +87,7 @@ impl Emacs {
print_separator("Emacs"); print_separator("Emacs");
let mut command = ctx.run_type().execute(emacs); let mut command = ctx.run_type().execute(&emacs);
command command
.args(["--batch", "--debug-init", "-l"]) .args(["--batch", "--debug-init", "-l"])

View File

@@ -60,12 +60,12 @@ 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").check_run()
} }
pub fn run_go(run_type: RunType) -> Result<()> { pub fn run_go(run_type: RunType) -> Result<()> {
let go = utils::require("go")?; let go = utils::require("go")?;
let go_output = run_type.execute(go).args(["env", "GOPATH"]).check_output()?; let go_output = run_type.execute(&go).args(["env", "GOPATH"]).check_output()?;
let gopath = go_output.trim(); let gopath = go_output.trim();
let go_global_update = utils::require("go-global-update") let go_global_update = utils::require("go-global-update")
@@ -74,7 +74,7 @@ pub fn run_go(run_type: RunType) -> Result<()> {
print_separator("Go"); print_separator("Go");
run_type.execute(go_global_update).check_run() 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<()> {
@@ -83,7 +83,7 @@ pub fn run_gem(base_dirs: &BaseDirs, run_type: RunType) -> Result<()> {
print_separator("RubyGems"); print_separator("RubyGems");
let mut command = run_type.execute(gem); let mut command = run_type.execute(&gem);
command.arg("update"); command.arg("update");
if env::var_os("RBENV_SHELL").is_none() { if env::var_os("RBENV_SHELL").is_none() {
@@ -123,7 +123,7 @@ 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"]).check_run()
} }
pub fn run_fossil(run_type: RunType) -> Result<()> { pub fn run_fossil(run_type: RunType) -> Result<()> {
@@ -131,7 +131,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"]).check_run()
} }
pub fn run_micro(run_type: RunType) -> Result<()> { pub fn run_micro(run_type: RunType) -> Result<()> {
@@ -139,7 +139,7 @@ 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"]).string_output()?;
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") {
@@ -160,7 +160,7 @@ 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"]).check_run()
} }
pub fn run_rustup(base_dirs: &BaseDirs, run_type: RunType) -> Result<()> { pub fn run_rustup(base_dirs: &BaseDirs, run_type: RunType) -> Result<()> {
@@ -190,22 +190,18 @@ 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"]).check_run()
} }
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")?;
if gcloud.starts_with("/snap") { print_separator("gcloud");
Ok(())
} else {
print_separator("gcloud");
run_type run_type
.execute(gcloud) .execute(&gcloud)
.args(["components", "update", "--quiet"]) .args(["components", "update", "--quiet"])
.check_run() .check_run()
}
} }
pub fn run_jetpack(run_type: RunType) -> Result<()> { pub fn run_jetpack(run_type: RunType) -> Result<()> {
@@ -213,7 +209,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"]).check_run()
} }
pub fn run_rtcl(ctx: &ExecutionContext) -> Result<()> { pub fn run_rtcl(ctx: &ExecutionContext) -> Result<()> {
@@ -221,7 +217,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).check_run()
} }
pub fn run_opam_update(ctx: &ExecutionContext) -> Result<()> { pub fn run_opam_update(ctx: &ExecutionContext) -> Result<()> {
@@ -243,14 +239,14 @@ 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"]).check_run()
} }
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").check_run()
} }
pub fn run_conda_update(ctx: &ExecutionContext) -> Result<()> { pub fn run_conda_update(ctx: &ExecutionContext) -> Result<()> {
@@ -268,7 +264,7 @@ pub fn run_conda_update(ctx: &ExecutionContext) -> Result<()> {
print_separator("Conda"); print_separator("Conda");
ctx.run_type() ctx.run_type()
.execute(conda) .execute(&conda)
.args(["update", "--all", "-y"]) .args(["update", "--all", "-y"])
.check_run() .check_run()
} }
@@ -293,7 +289,7 @@ pub fn run_pip3_update(run_type: RunType) -> Result<()> {
} }
pub fn run_stack_update(run_type: RunType) -> Result<()> { pub fn run_stack_update(run_type: RunType) -> Result<()> {
if utils::require("ghcup").is_ok() { if let Ok(_) = utils::require("ghcup") {
// `ghcup` is present and probably(?) being used to install `stack`. // `ghcup` is present and probably(?) being used to install `stack`.
// Don't upgrade `stack`, let `ghcup` handle it. Per `ghcup install stack`: // Don't upgrade `stack`, let `ghcup` handle it. Per `ghcup install stack`:
// !!! Additionally, you should upgrade stack only through ghcup and not use 'stack upgrade' !!! // !!! Additionally, you should upgrade stack only through ghcup and not use 'stack upgrade' !!!
@@ -303,14 +299,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").check_run()
} }
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").check_run()
} }
pub fn run_tlmgr_update(ctx: &ExecutionContext) -> Result<()> { pub fn run_tlmgr_update(ctx: &ExecutionContext) -> Result<()> {
@@ -327,7 +323,7 @@ pub fn run_tlmgr_update(ctx: &ExecutionContext) -> Result<()> {
let tlmgr_directory = { let tlmgr_directory = {
let mut d = PathBuf::from( let mut d = PathBuf::from(
std::str::from_utf8( std::str::from_utf8(
&Command::new(kpsewhich) &Command::new(&kpsewhich)
.arg("-var-value=SELFAUTOPARENT") .arg("-var-value=SELFAUTOPARENT")
.output()? .output()?
.stdout, .stdout,
@@ -364,7 +360,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").check_run()
} }
pub fn run_myrepos_update(base_dirs: &BaseDirs, run_type: RunType) -> Result<()> { pub fn run_myrepos_update(base_dirs: &BaseDirs, run_type: RunType) -> Result<()> {
@@ -444,7 +440,7 @@ pub fn run_composer_update(ctx: &ExecutionContext) -> Result<()> {
if stdout.contains("valet") || stderr.contains("valet") { if stdout.contains("valet") || stderr.contains("valet") {
if let Some(valet) = utils::which("valet") { if let Some(valet) = utils::which("valet") {
ctx.run_type().execute(valet).arg("install").check_run()?; ctx.run_type().execute(&valet).arg("install").check_run()?;
} }
} }
@@ -489,21 +485,21 @@ 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"]).check_run()
} }
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").check_run()
} }
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").check_run()
} }
pub fn run_ghcli_extensions_upgrade(ctx: &ExecutionContext) -> Result<()> { pub fn run_ghcli_extensions_upgrade(ctx: &ExecutionContext) -> Result<()> {
@@ -527,7 +523,7 @@ pub fn update_julia_packages(ctx: &ExecutionContext) -> Result<()> {
print_separator("Julia Packages"); print_separator("Julia Packages");
ctx.run_type() ctx.run_type()
.execute(julia) .execute(&julia)
.args(["-e", "using Pkg; Pkg.update()"]) .args(["-e", "using Pkg; Pkg.update()"])
.check_run() .check_run()
} }

View File

@@ -13,7 +13,7 @@ pub fn upgrade_kak_plug(ctx: &ExecutionContext) -> Result<()> {
print_separator("Kakoune"); print_separator("Kakoune");
let mut command = ctx.run_type().execute(kak); let mut command = ctx.run_type().execute(&kak);
command.args(["-ui", "dummy", "-e", UPGRADE_KAK]); command.args(["-ui", "dummy", "-e", UPGRADE_KAK]);
let output = command.output()?; let output = command.output()?;

View File

@@ -1,6 +1,5 @@
#![allow(unused_imports)] #![allow(unused_imports)]
use std::fmt::Display;
#[cfg(unix)] #[cfg(unix)]
use std::os::unix::prelude::MetadataExt; use std::os::unix::prelude::MetadataExt;
use std::path::PathBuf; use std::path::PathBuf;
@@ -18,71 +17,24 @@ 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};
enum NPMVariant {
Npm,
Pnpm,
}
impl NPMVariant {
const fn long_name(&self) -> &str {
match self {
NPMVariant::Npm => "Node Package Manager",
NPMVariant::Pnpm => "PNPM",
}
}
const fn short_name(&self) -> &str {
match self {
NPMVariant::Npm => "npm",
NPMVariant::Pnpm => "pnpm",
}
}
const fn is_npm(&self) -> bool {
matches!(self, NPMVariant::Npm)
}
}
impl Display for NPMVariant {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.write_str(self.short_name())
}
}
#[allow(clippy::upper_case_acronyms)] #[allow(clippy::upper_case_acronyms)]
struct NPM { struct NPM {
command: PathBuf, command: PathBuf,
variant: NPMVariant,
} }
impl NPM { impl NPM {
fn new(command: PathBuf, variant: NPMVariant) -> Self { fn new(command: PathBuf) -> Self {
Self { command, variant } Self { command }
}
/// Is the “NPM” version larger than 8.11.0?
fn is_npm_8(&self) -> bool {
let v = self.version();
self.variant.is_npm() && matches!(v, Ok(v) if v >= Version::new(8, 11, 0))
}
/// Get the most suitable “global location” argument
/// of this NPM instance.
///
/// If the “NPM” version is larger than 8.11.0, we use
/// `--location=global`; otherwise, use `-g`.
fn global_location_arg(&self) -> &str {
if self.is_npm_8() {
"--location=global"
} else {
"-g"
}
} }
#[cfg(target_os = "linux")] #[cfg(target_os = "linux")]
fn root(&self) -> Result<PathBuf> { fn root(&self) -> Result<PathBuf> {
let args = ["root", self.global_location_arg()]; let version = self.version()?;
let args = if version < Version::new(8, 11, 0) {
["root", "-g"]
} else {
["root", "--location=global"]
};
Command::new(&self.command) Command::new(&self.command)
.args(args) .args(args)
.check_output() .check_output()
@@ -98,8 +50,13 @@ impl NPM {
} }
fn upgrade(&self, run_type: RunType, use_sudo: bool) -> Result<()> { fn upgrade(&self, run_type: RunType, use_sudo: bool) -> Result<()> {
print_separator(self.variant.long_name()); print_separator("Node Package Manager");
let args = ["update", self.global_location_arg()]; let version = self.version()?;
let args = if version < Version::new(8, 11, 0) {
["update", "-g"]
} else {
["update", "--location=global"]
};
if use_sudo { if use_sudo {
run_type.execute("sudo").args(args).check_run()?; run_type.execute("sudo").args(args).check_run()?;
} else { } else {
@@ -113,7 +70,7 @@ impl NPM {
pub fn should_use_sudo(&self) -> Result<bool> { pub fn should_use_sudo(&self) -> Result<bool> {
let npm_root = self.root()?; let npm_root = self.root()?;
if !npm_root.exists() { if !npm_root.exists() {
return Err(SkipStep(format!("{} root at {} doesn't exist", self.variant, npm_root.display())).into()); return Err(SkipStep(format!("NPM root at {} doesn't exist", npm_root.display(),)).into());
} }
let metadata = std::fs::metadata(&npm_root)?; let metadata = std::fs::metadata(&npm_root)?;
@@ -136,17 +93,6 @@ impl Yarn {
} }
} }
fn has_global_subcmd(&self) -> bool {
// Get the version of Yarn. After Yarn 2.x (berry),
// “yarn global” has been replaced with “yarn dlx”.
//
// As “yarn dlx” don't need to “upgrade”, we
// ignore the whole task if Yarn is 2.x or above.
let version = Command::new(&self.command).args(["--version"]).check_output();
matches!(version, Ok(ver) if ver.starts_with('1') || ver.starts_with('0'))
}
#[cfg(target_os = "linux")] #[cfg(target_os = "linux")]
fn root(&self) -> Result<PathBuf> { fn root(&self) -> Result<PathBuf> {
let args = ["global", "dir"]; let args = ["global", "dir"];
@@ -177,7 +123,7 @@ impl Yarn {
pub fn should_use_sudo(&self) -> Result<bool> { pub fn should_use_sudo(&self) -> Result<bool> {
let yarn_root = self.root()?; let yarn_root = self.root()?;
if !yarn_root.exists() { if !yarn_root.exists() {
return Err(SkipStep(format!("Yarn root at {} doesn't exist", yarn_root.display(),)).into()); return Err(SkipStep(format!("NPM root at {} doesn't exist", yarn_root.display(),)).into());
} }
let metadata = std::fs::metadata(&yarn_root)?; let metadata = std::fs::metadata(&yarn_root)?;
@@ -216,7 +162,7 @@ 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("pnpm").or_else(|_| require("npm")).map(NPM::new)?;
#[cfg(target_os = "linux")] #[cfg(target_os = "linux")]
{ {
@@ -229,28 +175,9 @@ pub fn run_npm_upgrade(ctx: &ExecutionContext) -> Result<()> {
} }
} }
pub fn run_pnpm_upgrade(ctx: &ExecutionContext) -> Result<()> {
let pnpm = require("pnpm").map(|b| NPM::new(b, NPMVariant::Pnpm))?;
#[cfg(target_os = "linux")]
{
pnpm.upgrade(ctx.run_type(), should_use_sudo(&pnpm, ctx)?)
}
#[cfg(not(target_os = "linux"))]
{
pnpm.upgrade(ctx.run_type(), false)
}
}
pub fn run_yarn_upgrade(ctx: &ExecutionContext) -> Result<()> { pub fn run_yarn_upgrade(ctx: &ExecutionContext) -> Result<()> {
let yarn = require("yarn").map(Yarn::new)?; let yarn = require("yarn").map(Yarn::new)?;
if !yarn.has_global_subcmd() {
debug!("Yarn is 2.x or above, skipping global upgrade");
return Ok(());
}
#[cfg(target_os = "linux")] #[cfg(target_os = "linux")]
{ {
yarn.upgrade(ctx.run_type(), should_use_sudo_yarn(&yarn, ctx)?) yarn.upgrade(ctx.run_type(), should_use_sudo_yarn(&yarn, ctx)?)

View File

@@ -245,7 +245,7 @@ impl Aura {
impl ArchPackageManager for Aura { impl ArchPackageManager for Aura {
fn upgrade(&self, ctx: &ExecutionContext) -> Result<()> { fn upgrade(&self, ctx: &ExecutionContext) -> Result<()> {
let sudo = which("sudo").unwrap_or_else(PathBuf::new); let sudo = which("sudo").unwrap_or(PathBuf::new());
let mut aur_update = ctx.run_type().execute(&sudo); let mut aur_update = ctx.run_type().execute(&sudo);
if sudo.ends_with("sudo") { if sudo.ends_with("sudo") {

View File

@@ -11,15 +11,15 @@ 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"]).check_run()?;
ctx.run_type() ctx.run_type()
.execute(sudo) .execute(sudo)
.args(["port", "-u", "upgrade", "outdated"]) .args(&["port", "-u", "upgrade", "outdated"])
.check_run()?; .check_run()?;
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()?; .check_run()?;
} }
@@ -52,7 +52,7 @@ pub fn upgrade_macos(ctx: &ExecutionContext) -> Result<()> {
} }
let mut command = ctx.run_type().execute("softwareupdate"); let mut command = ctx.run_type().execute("softwareupdate");
command.args(["--install", "--all"]); command.args(&["--install", "--all"]);
if should_ask { if should_ask {
command.arg("--no-scan"); command.arg("--no-scan");
@@ -81,12 +81,12 @@ pub fn run_sparkle(ctx: &ExecutionContext) -> Result<()> {
for application in (fs::read_dir("/Applications")?).flatten() { for application in (fs::read_dir("/Applications")?).flatten() {
let probe = Command::new(&sparkle) let probe = Command::new(&sparkle)
.args(["--probe", "--application"]) .args(&["--probe", "--application"])
.arg(application.path()) .arg(application.path())
.check_output(); .check_output();
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.spawn()?.wait()?;
} }

View File

@@ -1,9 +1,8 @@
PRETTY_NAME="Debian GNU/Linux 11 (bullseye)" PRETTY_NAME="Debian GNU/Linux 8 (jessie)"
NAME="Debian GNU/Linux" NAME="Debian GNU/Linux"
VERSION_ID="11" VERSION_ID="8"
VERSION="11 (bullseye)" VERSION="8 (jessie)"
VERSION_CODENAME=bullseye
ID=debian ID=debian
HOME_URL="https://www.debian.org/" HOME_URL="http://www.debian.org/"
SUPPORT_URL="https://www.debian.org/support" SUPPORT_URL="http://www.debian.org/support"
BUG_REPORT_URL="https://bugs.debian.org/" BUG_REPORT_URL="https://bugs.debian.org/"

View File

@@ -124,7 +124,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"]).check_run()
} }
pub fn run_pkgin(ctx: &ExecutionContext) -> Result<()> { pub fn run_pkgin(ctx: &ExecutionContext) -> Result<()> {
@@ -154,7 +154,7 @@ 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"]).check_run()
} }
/// Upgrades `fundle` and `fundle` plugins. /// Upgrades `fundle` and `fundle` plugins.
@@ -258,19 +258,19 @@ 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() .check_output()
.map(|p| Path::new(p.trim()).exists())?; .map(|p| Path::new(p.trim()).exists())?;
let mut brew_args = vec![]; let mut brew_args = vec![];
if cask_upgrade_exists { if cask_upgrade_exists {
brew_args.extend(["cu", "-y"]); brew_args.extend(&["cu", "-y"]);
if ctx.config().brew_cask_greedy() { if ctx.config().brew_cask_greedy() {
brew_args.push("-a"); brew_args.push("-a");
} }
} else { } else {
brew_args.extend(["upgrade", "--cask"]); brew_args.extend(&["upgrade", "--cask"]);
if ctx.config().brew_cask_greedy() { if ctx.config().brew_cask_greedy() {
brew_args.push("--greedy"); brew_args.push("--greedy");
} }
@@ -352,7 +352,7 @@ pub fn run_nix(ctx: &ExecutionContext) -> Result<()> {
} }
} }
run_type.execute(nix_channel).arg("--update").check_run()?; run_type.execute(&nix_channel).arg("--update").check_run()?;
if std::path::Path::new(&manifest_json_path).exists() { if std::path::Path::new(&manifest_json_path).exists() {
run_type run_type
@@ -371,7 +371,7 @@ 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").check_run()
} }
pub fn run_asdf(run_type: RunType) -> Result<()> { pub fn run_asdf(run_type: RunType) -> Result<()> {
@@ -392,21 +392,21 @@ 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").check_run()
} }
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").check_run()
} }
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").check_run()
} }
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<()> {
@@ -471,7 +471,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").check_run()
} }
/// Update dotfiles with `rcm(7)`. /// Update dotfiles with `rcm(7)`.

View File

@@ -26,7 +26,7 @@ pub fn run_chocolatey(ctx: &ExecutionContext) -> Result<()> {
args.insert(0, "choco"); args.insert(0, "choco");
} }
let mut command = ctx.run_type().execute(cmd); let mut command = ctx.run_type().execute(&cmd);
command.args(&args); command.args(&args);
@@ -47,7 +47,7 @@ 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"]).check_run()
} }
pub fn run_scoop(cleanup: bool, run_type: RunType) -> Result<()> { pub fn run_scoop(cleanup: bool, run_type: RunType) -> Result<()> {
@@ -55,34 +55,34 @@ 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"]).check_run()?;
run_type.execute(&scoop).args(["update", "*"]).check_run()?; run_type.execute(&scoop).args(&["update", "*"]).check_run()?;
if cleanup { if cleanup {
run_type.execute(&scoop).args(["cleanup", "*"]).check_run()?; run_type.execute(&scoop).args(&["cleanup", "*"]).check_run()?;
} }
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"]).check_output()?;
Ok(output Ok(output
.lines() .lines()
.filter(|s| !s.is_empty()) .filter(|s| !s.is_empty())
.map(|x| x.replace(['\u{0}', '\r'], "")) .map(|x| x.replace('\u{0}', "").replace('\r', ""))
.collect()) .collect())
} }
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() .check_output()
.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));
if ctx.config().yes(Step::Wsl) { if ctx.config().yes(Step::Wsl) {
@@ -134,7 +134,7 @@ pub fn windows_update(ctx: &ExecutionContext) -> Result<()> {
} }
pub fn reboot() { pub fn reboot() {
Command::new("shutdown").args(["/R", "/T", "0"]).spawn().ok(); Command::new("shutdown").args(&["/R", "/T", "0"]).spawn().ok();
} }
pub fn insert_startup_scripts(ctx: &ExecutionContext, git_repos: &mut Repositories) -> Result<()> { pub fn insert_startup_scripts(ctx: &ExecutionContext, git_repos: &mut Repositories) -> Result<()> {

View File

@@ -46,8 +46,8 @@ impl Powershell {
#[cfg(windows)] #[cfg(windows)]
pub fn has_module(powershell: &Path, command: &str) -> bool { pub fn has_module(powershell: &Path, command: &str) -> bool {
Command::new(powershell) Command::new(&powershell)
.args([ .args(&[
"-NoProfile", "-NoProfile",
"-Command", "-Command",
&format!("Get-Module -ListAvailable {}", command), &format!("Get-Module -ListAvailable {}", command),
@@ -79,7 +79,6 @@ impl Powershell {
println!("Updating modules..."); println!("Updating modules...");
ctx.run_type() ctx.run_type()
.execute(powershell) .execute(powershell)
// This probably doesn't need `shell_words::join`.
.args(["-NoProfile", "-Command", &cmd.join(" ")]) .args(["-NoProfile", "-Command", &cmd.join(" ")])
.check_run() .check_run()
} }
@@ -100,14 +99,14 @@ impl Powershell {
let mut command = if let Some(sudo) = ctx.sudo() { let mut command = if let Some(sudo) = ctx.sudo() {
let mut command = ctx.run_type().execute(sudo); let mut command = ctx.run_type().execute(sudo);
command.arg(powershell); command.arg(&powershell);
command command
} else { } else {
ctx.run_type().execute(powershell) ctx.run_type().execute(&powershell)
}; };
command command
.args([ .args(&[
"-NoProfile", "-NoProfile",
"-Command", "-Command",
&format!( &format!(

View File

@@ -24,7 +24,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, &args.join(" "))?;
Err(SkipStep(String::from("Remote Topgrade launched in Tmux")).into()) Err(SkipStep(String::from("Remote Topgrade launched in Tmux")).into())
} }
@@ -47,6 +47,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).check_run()
} }
} }

View File

@@ -20,7 +20,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").check_run()
} }
struct Tmux { struct Tmux {
@@ -29,10 +29,12 @@ struct Tmux {
} }
impl Tmux { impl Tmux {
fn new(args: Vec<String>) -> Self { fn new(args: &Option<String>) -> Self {
Self { Self {
tmux: which("tmux").expect("Could not find tmux"), tmux: which("tmux").expect("Could not find tmux"),
args: if args.is_empty() { None } else { Some(args) }, args: args
.as_ref()
.map(|args| args.split_whitespace().map(String::from).collect()),
} }
} }
@@ -73,7 +75,7 @@ impl Tmux {
} }
} }
pub fn run_in_tmux(args: Vec<String>) -> ! { pub fn run_in_tmux(args: &Option<String>) -> ! {
let command = { let command = {
let mut command = vec![ let mut command = vec![
String::from("env"), String::from("env"),
@@ -81,7 +83,7 @@ pub fn run_in_tmux(args: Vec<String>) -> ! {
String::from("TOPGRADE_INSIDE_TMUX=1"), String::from("TOPGRADE_INSIDE_TMUX=1"),
]; ];
command.extend(env::args()); command.extend(env::args());
shell_words::join(command) command.join(" ")
}; };
let tmux = Tmux::new(args); let tmux = Tmux::new(args);
@@ -106,7 +108,7 @@ pub fn run_in_tmux(args: Vec<String>) -> ! {
} }
pub fn run_command(ctx: &ExecutionContext, command: &str) -> Result<()> { pub fn run_command(ctx: &ExecutionContext, command: &str) -> Result<()> {
Tmux::new(ctx.config().tmux_arguments()?) Tmux::new(ctx.config().tmux_arguments())
.build() .build()
.args(["new-window", "-a", "-t", "topgrade:1", command]) .args(["new-window", "-a", "-t", "topgrade:1", command])
.env_remove("TMUX") .env_remove("TMUX")

View File

@@ -118,9 +118,9 @@ pub fn upgrade_vim(base_dirs: &BaseDirs, ctx: &ExecutionContext) -> Result<()> {
upgrade( upgrade(
ctx.run_type() ctx.run_type()
.execute(&vim) .execute(&vim)
.args(["-u"]) .args(&["-u"])
.arg(vimrc) .arg(vimrc)
.args(["-U", "NONE", "-V1", "-nNesS"]) .args(&["-U", "NONE", "-V1", "-nNesS"])
.arg(upgrade_script()?.path()), .arg(upgrade_script()?.path()),
ctx, ctx,
) )
@@ -133,10 +133,10 @@ pub fn upgrade_neovim(base_dirs: &BaseDirs, ctx: &ExecutionContext) -> Result<()
print_separator("Neovim"); print_separator("Neovim");
upgrade( upgrade(
ctx.run_type() ctx.run_type()
.execute(nvim) .execute(&nvim)
.args(["-u"]) .args(&["-u"])
.arg(nvimrc) .arg(nvimrc)
.args(["--headless", "-V1", "-nS"]) .args(&["--headless", "-V1", "-nS"])
.arg(upgrade_script()?.path()), .arg(upgrade_script()?.path()),
ctx, ctx,
) )

View File

@@ -223,7 +223,7 @@ impl Terminal {
self.term.set_title("Topgrade - Awaiting user"); self.term.set_title("Topgrade - Awaiting user");
} }
self.notify_desktop(format!("{} failed", step_name), None); self.notify_desktop(&format!("{} failed", step_name), None);
self.term self.term
.write_fmt(format_args!( .write_fmt(format_args!(