diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index a178c30..cd740e7 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -14,7 +14,7 @@ jobs: matrix: rust: # MSRV - - 1.60.0 + - "1.72.1" - stable os: [ubuntu-latest, macos-latest, windows-latest] experimental: [false] @@ -24,54 +24,45 @@ jobs: experimental: true steps: - - uses: actions/checkout@v2 - - uses: actions-rs/toolchain@v1 - with: - profile: minimal - toolchain: ${{ matrix.rust }} - override: true - components: llvm-tools-preview + - uses: actions/checkout@v4 + - name: Setup Rust + shell: bash + run: | + rustup toolchain install ${{ matrix.rust }} --profile minimal + rustup default ${{ matrix.rust }} + rustup component add llvm-tools-preview clippy rustfmt + echo "::add-matcher::.github/workflows/rust.json" + + - name: Clippy + run: cargo clippy -- -D warnings + + - name: rustfmt + run: cargo fmt --all -- --check - name: Build and install cargo-binutils - uses: actions-rs/cargo@v1 - with: - command: install - args: --path . -f + run: cargo install --path . -f - name: Run cargo-nm - uses: actions-rs/cargo@v1 - with: - command: nm - args: --bin cargo-nm -- --undefined-only + run: cargo nm --bin cargo-nm -- --undefined-only - name: Run cargo-objdump - uses: actions-rs/cargo@v1 - with: - command: objdump - args: --bin cargo-objdump -- -h + run: cargo objdump --bin cargo-objdump -- -h - name: Run cargo-objcopy (on Linux only) if: matrix.os == 'ubuntu-latest' - uses: actions-rs/cargo@v1 - with: - command: objcopy - args: --bin cargo-objdump -v -- -O binary objdump.bin + run: cargo objcopy --bin cargo-objdump -v -- -O binary objdump.bin - name: Run cargo-size - uses: actions-rs/cargo@v1 - with: - command: size - args: --bin cargo-size -v + run: cargo size --bin cargo-size -v - name: Run cargo-strip (on Linux only) if: matrix.os == 'ubuntu-latest' - uses: actions-rs/cargo@v1 - with: - command: strip - args: --bin cargo-strip -v + run: cargo strip --bin cargo-strip -v + conclusion: runs-on: ubuntu-latest needs: ci + if: always() steps: - - name: Result - run: exit 0 + - name: Done + run: jq --exit-status 'all(.result == "success")' <<< '${{ toJson(needs) }}' diff --git a/.github/workflows/clippy.yml b/.github/workflows/clippy.yml deleted file mode 100644 index adc3a6e..0000000 --- a/.github/workflows/clippy.yml +++ /dev/null @@ -1,20 +0,0 @@ -on: - push: - branches: [ staging, trying, master ] - pull_request: - -name: Clippy check -jobs: - clippy_check: - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v2 - - uses: actions-rs/toolchain@v1 - with: - profile: minimal - toolchain: stable - override: true - components: clippy - - uses: actions-rs/clippy-check@v1 - with: - token: ${{ secrets.GITHUB_TOKEN }} diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 15c583f..a5728ae 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -19,20 +19,12 @@ jobs: runs-on: ${{ matrix.os }} steps: - uses: actions/checkout@v3 - - uses: actions-rs/toolchain@v1 + - uses: dtolnay/rust-toolchain@9cd00a88a73addc8617065438eff914dd08d0955 # 2023-02-02 with: toolchain: stable - profile: minimal - target: ${{ matrix.target }} - override: true - name: Cache Dependencies - uses: Swatinem/rust-cache@v1 - with: - key: ${{ matrix.target }} - - uses: actions-rs/cargo@v1 - with: - command: build - args: --target ${{ matrix.target }} --release + uses: Swatinem/rust-cache@v2 + - run: cargo build --target ${{ matrix.target }} --release - name: (Not Windows) Move executables and compress if: ${{ matrix.os != 'windows-latest' }} @@ -73,7 +65,7 @@ jobs: run: echo "CURRENT_DATE=$(date +'%Y-%m-%d')" >> $GITHUB_ENV - id: changelog-reader - uses: mindsers/changelog-reader-action@v2.0.0 + uses: mindsers/changelog-reader-action@v2.2.2 with: version: ${{ (github.ref_type == 'tag' && github.ref_name) || 'Unreleased' }} diff --git a/.github/workflows/rust.json b/.github/workflows/rust.json new file mode 100644 index 0000000..df18131 --- /dev/null +++ b/.github/workflows/rust.json @@ -0,0 +1,21 @@ +{ + "problemMatcher": [ + { + "owner": "rust", + "pattern": [ + { + "regexp": "^(warning|warn|error)(\\[(.*)\\])?: (.*)$", + "severity": 1, + "message": 4, + "code": 3 + }, + { + "regexp": "^([\\s->=]*(.*):(\\d*):(\\d*)|.*)$", + "file": 2, + "line": 3, + "column": 4 + } + ] + } + ] + } \ No newline at end of file diff --git a/.github/workflows/rustfmt.yml b/.github/workflows/rustfmt.yml deleted file mode 100644 index 9a55c00..0000000 --- a/.github/workflows/rustfmt.yml +++ /dev/null @@ -1,23 +0,0 @@ -on: - push: - branches: [ staging, trying, master ] - pull_request: - -name: Code formatting check - -jobs: - fmt: - name: Rustfmt - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v2 - - uses: actions-rs/toolchain@v1 - with: - profile: minimal - toolchain: stable - override: true - components: rustfmt - - uses: actions-rs/cargo@v1 - with: - command: fmt - args: --all -- --check diff --git a/CHANGELOG.md b/CHANGELOG.md index 371339f..f9b3695 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,8 +9,8 @@ and this project adheres to [Semantic Versioning](http://semver.org/). ### Changed -- MSRV Changed to 1.60 -- Bump `rust-cfg` to 0.5 and `cargo_metadata` to 0.15 +- MSRV Changed to 1.64 +- Bump `rust-cfg` to 0.5, `cargo_metadata` to 0.15, `clap` to 4.1.4 and `toml` to 0.7.1 ### Fixed diff --git a/Cargo.toml b/Cargo.toml index 57070b1..70d5203 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,5 +1,5 @@ [package] -edition = "2018" +edition = "2021" authors = [ "The Embedded WG Tools Team ", "Jorge Aparicio ", @@ -13,14 +13,15 @@ name = "cargo-binutils" readme = "README.md" repository = "https://github.com/rust-embedded/cargo-binutils/" version = "0.3.6" +rust-version = "1.72.1" [dependencies] cargo_metadata = "0.15" -clap = "2.34" +clap = { version = "4.1.4", features = ["cargo", "wrap_help", "string"] } regex = "1.5" rustc-cfg = "0.5" rustc-demangle = "0.1" rustc_version = "0.4" serde = "1.0" -toml = "0.5" +toml = "0.7.1" anyhow = "1.0" diff --git a/README.md b/README.md index 75455ae..b7192de 100644 --- a/README.md +++ b/README.md @@ -209,7 +209,7 @@ linker = "rust-lld" ## Minimum Supported Rust Version (MSRV) -This crate is guaranteed to compile on stable Rust 1.60.0 and up. It *might* +This crate is guaranteed to compile on stable Rust 1.64.0 and up. It *might* compile with older versions but that may change in any new patch release. ## License diff --git a/src/lib.rs b/src/lib.rs index 244ca22..04ed911 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,5 +1,3 @@ -#![deny(warnings)] - use std::io::{self, BufReader, Write}; use std::path::Path; use std::process::{Command, Stdio}; @@ -8,7 +6,7 @@ use std::{env, str}; use anyhow::{bail, Result}; use cargo_metadata::camino::Utf8Component; use cargo_metadata::{Artifact, CargoOpt, Message, Metadata, MetadataCommand}; -use clap::{App, AppSettings, Arg, ArgMatches}; +use clap::{Arg, ArgAction, ArgMatches, Command as ClapCommand}; use rustc_cfg::Cfg; pub use tool::Tool; @@ -146,10 +144,7 @@ impl<'a> BuildType<'a> { fn args(tool: Tool, examples: Option<&str>) -> ArgMatches { let name = tool.name(); - let about = format!( - "Proxy for the `llvm-{}` tool shipped with the Rust toolchain.", - name - ); + let about = format!("Proxy for the `llvm-{name}` tool shipped with the Rust toolchain."); let after_help = format!( "\ The arguments specified *after* the `--` will be passed to the proxied tool invocation. @@ -159,119 +154,106 @@ To see all the flags the proxied tool accepts run `cargo-{} -- --help`.{}", examples.unwrap_or("") ); - let app = App::new(format!("cargo-{}", name)) - .about(&*about) + let app = ClapCommand::new(format!("cargo-{name}")) + .about(about) .version(env!("CARGO_PKG_VERSION")) - .settings(&[ - AppSettings::UnifiedHelpMessage, - AppSettings::DeriveDisplayOrder, - AppSettings::DontCollapseArgsInUsage, - ]) // as this is used as a Cargo subcommand the first argument will be the name of the binary // we ignore this argument .args(&[ - Arg::with_name("binary-name").hidden(true), - Arg::with_name("verbose") + Arg::new("binary-name").hide(true), + Arg::new("verbose") .long("verbose") - .short("v") - .multiple(true) + .short('v') + .action(ArgAction::Count) .help("Use verbose output (-vv cargo verbose or -vvv for build.rs output)"), - Arg::with_name("args") + Arg::new("args") .last(true) - .multiple(true) + .num_args(1..) .help("The arguments to be proxied to the tool"), ]) - .after_help(&*after_help); + .after_help(after_help); if tool.needs_build() { app.args(&[ - Arg::with_name("quiet") + Arg::new("quiet") .long("quiet") - .short("q") + .short('q') .help("Don't print build output from `cargo build`"), - Arg::with_name("package") + Arg::new("package") .long("package") - .short("p") - .takes_value(true) + .short('p') .value_name("SPEC") .help("Package to build (see `cargo help pkgid`)"), - Arg::with_name("jobs") + Arg::new("jobs") .long("jobs") - .short("j") + .short('j') .value_name("N") .help("Number of parallel jobs, defaults to # of CPUs"), - Arg::with_name("lib") + Arg::new("lib") .long("lib") - .conflicts_with_all(&["bin", "example", "test", "bench"]) + .conflicts_with_all(["bin", "example", "test", "bench"]) .help("Build only this package's library"), - Arg::with_name("bin") + Arg::new("bin") .long("bin") - .takes_value(true) .value_name("NAME") - .conflicts_with_all(&["lib", "example", "test", "bench"]) + .conflicts_with_all(["lib", "example", "test", "bench"]) .help("Build only the specified binary"), - Arg::with_name("example") + Arg::new("example") .long("example") - .takes_value(true) .value_name("NAME") - .conflicts_with_all(&["lib", "bin", "test", "bench"]) + .conflicts_with_all(["lib", "bin", "test", "bench"]) .help("Build only the specified example"), - Arg::with_name("test") + Arg::new("test") .long("test") - .takes_value(true) .value_name("NAME") - .conflicts_with_all(&["lib", "bin", "example", "bench"]) + .conflicts_with_all(["lib", "bin", "example", "bench"]) .help("Build only the specified test target"), - Arg::with_name("bench") + Arg::new("bench") .long("bench") - .takes_value(true) .value_name("NAME") - .conflicts_with_all(&["lib", "bin", "example", "test"]) + .conflicts_with_all(["lib", "bin", "example", "test"]) .help("Build only the specified bench target"), - Arg::with_name("release") + Arg::new("release") .long("release") .help("Build artifacts in release mode, with optimizations"), - Arg::with_name("profile") + Arg::new("profile") .long("profile") .value_name("PROFILE-NAME") .help("Build artifacts with the specified profile"), - Arg::with_name("features") + Arg::new("features") .long("features") - .multiple(true) - .number_of_values(1) - .takes_value(true) + .short('F') .value_name("FEATURES") .help("Space-separated list of features to activate"), - Arg::with_name("all-features") + Arg::new("all-features") .long("all-features") .help("Activate all available features"), - Arg::with_name("no-default-features") + Arg::new("no-default-features") .long("no-default-features") .help("Do not activate the `default` feature"), - Arg::with_name("target") + Arg::new("target") .long("target") - .takes_value(true) .value_name("TRIPLE") .help("Target triple for which the code is compiled"), - Arg::with_name("color") + Arg::new("color") .long("color") - .takes_value(true) - .possible_values(&["auto", "always", "never"]) + .action(ArgAction::Set) + .value_parser(clap::builder::PossibleValuesParser::new([ + "auto", "always", "never", + ])) .help("Coloring: auto, always, never"), - Arg::with_name("frozen") + Arg::new("frozen") .long("frozen") .help("Require Cargo.lock and cache are up to date"), - Arg::with_name("locked") + Arg::new("locked") .long("locked") .help("Require Cargo.lock is up to date"), - Arg::with_name("offline") + Arg::new("offline") .long("offline") .help("Run without accessing the network"), - Arg::with_name("unstable-features") - .short("Z") - .multiple(true) - .number_of_values(1) - .takes_value(true) + Arg::new("unstable-features") + .short('Z') + .action(ArgAction::Append) .value_name("FLAG") .help("Unstable (nightly-only) flags to Cargo, see 'cargo -Z help' for details"), ]) @@ -283,15 +265,15 @@ To see all the flags the proxied tool accepts run `cargo-{} -- --help`.{}", pub fn run(tool: Tool, matches: ArgMatches) -> Result { let mut metadata_command = MetadataCommand::new(); - if let Some(features) = matches.values_of("features") { + if let Some(features) = matches.get_many::("features") { metadata_command.features(CargoOpt::SomeFeatures( features.map(|s| s.to_owned()).collect(), )); } - if matches.is_present("no-default-features") { + if matches.contains_id("no-default-features") { metadata_command.features(CargoOpt::NoDefaultFeatures); } - if matches.is_present("all-features") { + if matches.contains_id("all-features") { metadata_command.features(CargoOpt::AllFeatures); } let metadata = metadata_command.exec()?; @@ -300,8 +282,8 @@ pub fn run(tool: Tool, matches: ArgMatches) -> Result { } let mut tool_args = vec![]; - if let Some(args) = matches.values_of("args") { - tool_args.extend(args); + if let Some(args) = matches.get_many::("args") { + tool_args.extend(args.map(|s| s.as_str())); } let tool_help = tool_args.first() == Some(&"--help"); @@ -318,7 +300,10 @@ pub fn run(tool: Tool, matches: ArgMatches) -> Result { let ctxt = if let Some(artifact) = &target_artifact { Context::from_artifact(metadata, artifact)? } else { - Context::from_flag(metadata, matches.value_of("target"))? + Context::from_flag( + metadata, + matches.get_one::("target").map(|s| s.as_str()), + )? }; let arch_name = llvm::arch_name(&ctxt.cfg, &ctxt.target); @@ -328,7 +313,7 @@ pub fn run(tool: Tool, matches: ArgMatches) -> Result { // `-triple=$target`, which contains more information about the target lltool.args(["--triple", &ctxt.target]); } else { - lltool.args(&[format!("--arch-name={}", arch_name)]); + lltool.args(&[format!("--arch-name={arch_name}")]); } } @@ -375,8 +360,8 @@ pub fn run(tool: Tool, matches: ArgMatches) -> Result { // User flags lltool.args(&tool_args); - if matches.is_present("verbose") { - eprintln!("{:?}", lltool); + if matches.contains_id("verbose") { + eprintln!("{lltool:?}"); } let stdout = io::stdout(); @@ -408,13 +393,13 @@ fn cargo_build(matches: &ArgMatches, metadata: &Metadata) -> Result 0 { - eprintln!("{:?}", cargo); + eprintln!("{cargo:?}"); } let mut child = cargo.spawn()?; @@ -445,7 +430,7 @@ fn cargo_build(matches: &ArgMatches, metadata: &Metadata) -> Result { if !quiet || verbose > 1 { if let Some(rendered) = msg.message.rendered { - print!("{}", rendered); + print!("{rendered}"); } } } @@ -460,90 +445,90 @@ fn cargo_build(matches: &ArgMatches, metadata: &Metadata) -> Result(matches: &'a ArgMatches<'a>, cargo: &mut Command) -> (BuildType<'a>, u64) { - if matches.is_present("quiet") { +fn cargo_build_args<'a>(matches: &'a ArgMatches, cargo: &mut Command) -> (BuildType<'a>, u64) { + if matches.contains_id("quiet") { cargo.arg("--quiet"); } - if let Some(package) = matches.value_of("package") { + if let Some(package) = matches.get_one::("package") { cargo.arg("--package"); cargo.arg(package); } - if let Some(jobs) = matches.value_of("jobs") { + if let Some(jobs) = matches.get_one::("jobs") { cargo.arg("-j"); cargo.arg(jobs); } - let build_type = if matches.is_present("lib") { + let build_type = if matches.contains_id("lib") { cargo.args(["--lib"]); BuildType::Lib - } else if let Some(bin_name) = matches.value_of("bin") { + } else if let Some(bin_name) = matches.get_one::("bin") { cargo.args(["--bin", bin_name]); BuildType::Bin(bin_name) - } else if let Some(example_name) = matches.value_of("example") { + } else if let Some(example_name) = matches.get_one::("example") { cargo.args(["--example", example_name]); BuildType::Example(example_name) - } else if let Some(test_name) = matches.value_of("test") { + } else if let Some(test_name) = matches.get_one::("test") { cargo.args(["--test", test_name]); BuildType::Test(test_name) - } else if let Some(bench_name) = matches.value_of("bench") { + } else if let Some(bench_name) = matches.get_one::("bench") { cargo.args(["--bench", bench_name]); BuildType::Bench(bench_name) } else { BuildType::Any }; - if matches.is_present("release") { + if matches.contains_id("release") { cargo.arg("--release"); } - if let Some(profile) = matches.value_of("profile") { + if let Some(profile) = matches.get_one::("profile") { cargo.arg("--profile"); cargo.arg(profile); } - if let Some(features) = matches.values_of("features") { + if let Some(features) = matches.get_many::("features") { for feature in features { cargo.args(["--features", feature]); } } - if matches.is_present("no-default-features") { + if matches.contains_id("no-default-features") { cargo.arg("--no-default-features"); } - if matches.is_present("all-features") { + if matches.contains_id("all-features") { cargo.arg("--all-features"); } // NOTE we do *not* use `project.target()` here because Cargo will figure things out on // its own (i.e. it will search and parse .cargo/config, etc.) - if let Some(target) = matches.value_of("target") { + if let Some(target) = matches.get_one::("target") { cargo.args(["--target", target]); } - let verbose = matches.occurrences_of("verbose"); + let verbose = matches.get_count("verbose") as u64; if verbose > 1 { cargo.arg(format!("-{}", "v".repeat((verbose - 1) as usize))); } - if let Some(color) = matches.value_of("color") { + if let Some(color) = matches.get_one::("color") { cargo.arg("--color"); cargo.arg(color); } - if matches.is_present("frozen") { + if matches.contains_id("frozen") { cargo.arg("--frozen"); } - if matches.is_present("locked") { + if matches.contains_id("locked") { cargo.arg("--locked"); } - if matches.is_present("offline") { + if matches.contains_id("offline") { cargo.arg("--offline"); } - if let Some(unstable_features) = matches.values_of("unstable-features") { + if let Some(unstable_features) = matches.get_many::("unstable-features") { for unstable_feature in unstable_features { cargo.args(["-Z", unstable_feature]); } diff --git a/src/postprocess.rs b/src/postprocess.rs index 11eb8de..2ca5f98 100644 --- a/src/postprocess.rs +++ b/src/postprocess.rs @@ -7,11 +7,11 @@ use regex::{Captures, Regex}; // UTF-8 then we don't touch it. // This pass demangles *all* the Rust symbols in the input -pub fn demangle(bytes: &[u8]) -> Cow<[u8]> { - let re = Regex::new(r#"_Z.+?E\b"#).expect("BUG: Malformed Regex"); +pub fn demangle(bytes: &[u8]) -> Cow<'_, [u8]> { + let re = Regex::new(r"_Z.+?E\b").expect("BUG: Malformed Regex"); if let Ok(text) = str::from_utf8(bytes) { - match re.replace_all(text, |cs: &Captures| { + match re.replace_all(text, |cs: &Captures<'_>| { format!("{}", rustc_demangle::demangle(cs.get(0).unwrap().as_str())) }) { Cow::Borrowed(s) => s.as_bytes().into(), @@ -27,7 +27,7 @@ pub fn size(bytes: &[u8]) -> Cow<[u8]> { if let Ok(text) = str::from_utf8(bytes) { let mut s = text .lines() - .map(|line| -> Cow { + .map(|line| -> Cow<'_, str> { match line .split_whitespace() .nth(2) @@ -37,7 +37,7 @@ pub fn size(bytes: &[u8]) -> Cow<[u8]> { // the second number is the address Some((needle, addr)) if line.starts_with('.') => { let pos = line.rfind(needle).unwrap(); - let hex_addr = format!("{:#x}", addr); + let hex_addr = format!("{addr:#x}"); let start = pos + needle.as_bytes().len() - hex_addr.as_bytes().len(); format!("{}{}", &line[..start], hex_addr).into() diff --git a/src/tool.rs b/src/tool.rs index 34391a2..3142e40 100644 --- a/src/tool.rs +++ b/src/tool.rs @@ -39,7 +39,7 @@ impl Tool { pub fn exe(self) -> String { match self { - Tool::Lld => format!("rust-lld{}", EXE_SUFFIX), + Tool::Lld => format!("rust-lld{EXE_SUFFIX}"), _ => format!("llvm-{}{}", self.name(), EXE_SUFFIX), } } @@ -92,7 +92,7 @@ impl Tool { match crate::run(self, matches) { Err(e) => { - eprintln!("error: {}", e); + eprintln!("error: {e}"); process::exit(101) } Ok(ec) => process::exit(ec),