-
Notifications
You must be signed in to change notification settings - Fork 20
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
feat: extending with rustup components and external subcommands #31
base: master
Are you sure you want to change the base?
Changes from 4 commits
d6d6cc3
4f7281e
e22e92b
d48a2c4
9010ac2
ec34330
3897b57
2b5cee0
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Large diffs are not rendered by default.
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -17,21 +17,93 @@ The following commands can be run within a Cargo package or at the root of a Car | |
Build crate with all feature flag combinations: | ||
|
||
``` | ||
cargo build-all-features <CARGO BUILD FLAGS> | ||
cargo all-features build -- <CARGO BUILD FLAGS> | ||
``` | ||
|
||
Check crate with all feature flag combinations: | ||
|
||
``` | ||
cargo check-all-features <CARGO CHECK FLAGS> | ||
cargo all-features check -- <CARGO CHECK FLAGS> | ||
``` | ||
|
||
Test crate with all feature flag combinations: | ||
|
||
``` | ||
cargo test-all-features <CARGO TEST FLAGS> | ||
cargo all-features test -- <CARGO TEST FLAGS> | ||
``` | ||
|
||
<details> | ||
<summary markdown="title"><bold>Supported tools</bold></summary> | ||
|
||
- First party | ||
- [`cargo test`](https://doc.rust-lang.org/cargo/commands/cargo-test.html) cargos integrated testing tool | ||
- [`cargo check`](https://doc.rust-lang.org/cargo/commands/cargo-check.html) cargos integrated checking tool | ||
- [`cargo build`](https://doc.rust-lang.org/cargo/commands/cargo-build.html) cargos integrated build tool | ||
- `cargo bench` [Used by cargos benching feature](https://doc.rust-lang.org/cargo/commands/cargo-bench.html) or crates like [citerion](https://github.com/bheisler/criterion.rs) | ||
- Additional RustUp components | ||
- [`cargo miri test`](https://github.com/rust-lang/miri) for testing using miri -> _rustup component `miri` is needed_ | ||
- Cargo plugins | ||
- [`cargo udeps`](https://github.com/est31/cargo-udeps) to analyze for unused dependencies -> _cargo plugin `cargo-udeps` is needed_ | ||
- [`cargo tarpaulin`](https://github.com/xd009642/tarpaulin) to analyze for unused dependencies -> _cargo plugin `cargo-tarpaulin` is needed_ | ||
- [`cargo nextest`](https://nexte.st/) the next generation test runner for cargo -> _cargo plugin `cargo-nextest` is needed_ | ||
|
||
> for more information run `cargo all-features --help` | ||
</details> | ||
|
||
<details> | ||
<summary markdown="span">Additional Features</summary> | ||
|
||
### Chunking | ||
|
||
If certain projects, features might add up and CI jobs can take longer. In order to shrink wall time of your builds you can specify `--chunks` (the total amount of junks to split into _[1..]_) and `--chunk` (the chunk nr of the one executed command _\[1..\<CHUNKS\>\]_) per execution. | ||
|
||
I.e. in github you can use a job matrix: | ||
|
||
```yaml | ||
name: CI | ||
|
||
on: [pull_request] | ||
|
||
jobs: | ||
build: | ||
runs-on: ubuntu-latest | ||
strategy: | ||
matrix: | ||
chunk: [1,2,3,4] | ||
chunks: 4 | ||
steps: | ||
- uses: actions/checkout@v2 | ||
- name: Install stable toolchain | ||
uses: actions-rs/toolchain@v1 | ||
with: | ||
profile: minimal | ||
toolchain: stable | ||
override: true | ||
- name: Install cargo-all-features | ||
uses: actions-rs/cargo@v1 | ||
with: | ||
command: install cargo-all-features | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I wonder if we should suggest passing the argument that specifies a version to install. That could make it easier to introduce breaking changes in the future 🤔 There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'm a fan of the idea, but I do not really think many users will manually change the version inside the commands input as this would not be covered by something like dependabot. One suggestion would be create a gh action for cargo-all-features itself, this could mean a 1:1 mapping between gh-action version and crate version which then could be updated using dependabot. |
||
- name: Build all features for release | ||
run: cargo all-features build --chunks ${{matrix.chunks}} --chunk ${{matrix.chunk}} -- --release | ||
``` | ||
|
||
### Dry run & Verbosity | ||
|
||
You are not sure if you configured something correct but don't have the time to wait for all tests or builds? Use `--dry-run`, it will skip all command execution. | ||
|
||
If you are not sure if the correct command are executed use `--verbose` | ||
|
||
### RustUp toolchain | ||
|
||
Don't mind to use `+<toolchain>` or any other combination of rustups toolchain selection. `cargo-all-features` will pick up on the active toolchain and use it. | ||
|
||
> for more information run `cargo all-features --help` | ||
|
||
### Cross | ||
> If you never heard of [cross](https://github.com/cross-rs/cross), an almost zero setup cross compilation cli setup | ||
|
||
While there is no way to directly know if you are calling this cargo subcommand from cross, there is a `--target-command` flag which can be set to `cross` which will forward the feature flags to `cross` instead of `cargo` | ||
</details> | ||
|
||
## Why? | ||
|
||
|
@@ -69,8 +141,8 @@ allowlist = ["foo", "bar"] | |
|
||
Licensed under either of | ||
|
||
* Apache License, Version 2.0 ([LICENSE-APACHE](LICENSE-APACHE) or http://www.apache.org/licenses/LICENSE-2.0) | ||
* MIT license ([LICENSE-MIT](LICENSE-MIT) or http://opensource.org/licenses/MIT) | ||
- Apache License, Version 2.0 ([LICENSE-APACHE](LICENSE-APACHE) or http://www.apache.org/licenses/LICENSE-2.0) | ||
- MIT license ([LICENSE-MIT](LICENSE-MIT) or http://opensource.org/licenses/MIT) | ||
|
||
at your option. | ||
|
||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,123 @@ | ||
#![forbid(unsafe_code)] | ||
#![deny(clippy::all)] | ||
|
||
use std::process; | ||
|
||
use cargo_all_features::{runner::CargoCommand, toolchain::CommandTarget, Options}; | ||
use clap::{crate_authors, crate_description, crate_version, Parser, Subcommand}; | ||
use yansi::Paint; | ||
|
||
#[derive(Debug, Parser)] | ||
#[clap( | ||
name = env!("CARGO_BIN_NAME"), | ||
author = crate_authors!(), | ||
version = crate_version!(), | ||
about = crate_description!(), | ||
bin_name = "cargo all-features", | ||
visible_alias = "all-features", | ||
)] | ||
struct Cli { | ||
#[clap(long, help="The total number of chunks to split into. Only used for calculations", possible_values(["1.."]))] | ||
pub chunks: Option<usize>, | ||
|
||
#[clap(long, help="The chunk to process", possible_values(["1..<CHUNKS>"]))] | ||
pub chunk: Option<usize>, | ||
|
||
#[clap(long, help = "If enabled will not execute commands")] | ||
pub dry_run: bool, | ||
|
||
#[clap(long, help = "If enabled will not disable any coloring")] | ||
pub no_color: bool, | ||
|
||
#[clap( | ||
long, | ||
short, | ||
help = "If enabled will show command which will or would be executed" | ||
)] | ||
pub verbose: bool, | ||
|
||
#[clap(arg_enum)] | ||
pub command: CargoCommand, | ||
|
||
#[clap(arg_enum, long)] | ||
pub command_target: Option<CommandTarget>, | ||
|
||
#[clap(subcommand)] | ||
pub flags_and_options: Option<FlagsAndOptions>, | ||
} | ||
|
||
#[derive(Debug, Subcommand)] | ||
enum FlagsAndOptions { | ||
#[clap(external_subcommand)] | ||
External(Vec<String>), | ||
} | ||
|
||
// Runs the command and prints out in rust known error format | ||
fn run_command( | ||
command: CargoCommand, | ||
args: &[String], | ||
options: Option<Options>, | ||
command_target: CommandTarget, | ||
) { | ||
if let Err(error) = cargo_all_features::run(command, args, options, command_target) { | ||
println!("{}: {}", Paint::red("error").bold(), error); | ||
} | ||
} | ||
|
||
// Main entrypoint for `cargo all-features`, cli as the frontend | ||
pub fn main() { | ||
// Name of the cargo subcommand | ||
let name: String = env!("CARGO_BIN_NAME").replace("cargo-", ""); | ||
|
||
// Checking if command is used via cargo or as binary (such as using cargo build --bin all-features | ||
let arguments = std::env::args().skip( | ||
if std::env::args().nth(1).unwrap_or_else(|| "".to_string()) == name { | ||
1 | ||
} else { | ||
0 | ||
}, | ||
); | ||
|
||
// Parsing input args | ||
let args = Cli::parse_from(arguments); | ||
|
||
// Checking if options are specified and transforming them into the libraries business logic | ||
let mut options = Options { | ||
no_color: args.no_color, | ||
dry_run: args.dry_run, | ||
verbose: args.verbose, | ||
chunks: None, | ||
chunk: None, | ||
}; | ||
|
||
// Only if chunk and chunks are set | ||
if args.chunks.is_some() && args.chunk.is_some() { | ||
options.chunks = args.chunks; | ||
options.chunk = args.chunk; | ||
} | ||
|
||
// Disable color | ||
if args.no_color { | ||
Paint::disable(); | ||
} | ||
|
||
// Default to cargo | ||
let command_target = args.command_target.unwrap_or(CommandTarget::Cargo); | ||
|
||
// checking if cross is installed | ||
if command_target == CommandTarget::Cross && which::which("cross").is_err() { | ||
println!("{}: Could not find `cross` installed. To install it run `cargo install cross` or head over to https://github.com/cross-rs/cross for more information", Paint::red("error").bold()); | ||
process::exit(127); | ||
} | ||
|
||
// Either run with additional flags and subcommands or without | ||
if let Some(external_command) = args.flags_and_options { | ||
match external_command { | ||
FlagsAndOptions::External(commands) => { | ||
run_command(args.command, &commands, Some(options), command_target); | ||
} | ||
} | ||
} else { | ||
run_command(args.command, &[], Some(options), command_target); | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,6 +1,9 @@ | ||
use cargo_all_features::{run, test_runner::CargoCommand}; | ||
use std::error::Error; | ||
#![forbid(unsafe_code)] | ||
#![deny(clippy::all)] | ||
|
||
fn main() -> Result<(), Box<dyn Error>> { | ||
run(CargoCommand::Build) | ||
use cargo_all_features::runner::CargoCommand; | ||
mod common; | ||
|
||
fn main() { | ||
common::deprecated_glue::run(CargoCommand::Build); | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,6 +1,9 @@ | ||
use cargo_all_features::{run, test_runner::CargoCommand}; | ||
use std::error::Error; | ||
#![forbid(unsafe_code)] | ||
#![deny(clippy::all)] | ||
|
||
fn main() -> Result<(), Box<dyn Error>> { | ||
run(CargoCommand::Check) | ||
use cargo_all_features::runner::CargoCommand; | ||
mod common; | ||
|
||
fn main() { | ||
common::deprecated_glue::run(CargoCommand::Check); | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,6 +1,8 @@ | ||
use cargo_all_features::{run, test_runner::CargoCommand}; | ||
use std::error::Error; | ||
#![forbid(unsafe_code)] | ||
#![deny(clippy::all)] | ||
|
||
fn main() -> Result<(), Box<dyn Error>> { | ||
run(CargoCommand::Test) | ||
use cargo_all_features::runner::CargoCommand; | ||
mod common; | ||
fn main() { | ||
common::deprecated_glue::run(CargoCommand::Test); | ||
} |
Original file line number | Diff line number | Diff line change | ||||
---|---|---|---|---|---|---|
@@ -0,0 +1,26 @@ | ||||||
use cargo_all_features::{run as run_main, runner::CargoCommand, toolchain::CommandTarget}; | ||||||
use yansi::Paint; | ||||||
|
||||||
// Glue code to run `cargo build-all-features`, etc. with same logic as `cargo all-features build` | ||||||
pub fn run(command: CargoCommand) { | ||||||
let name: String = env!("CARGO_BIN_NAME").replace("cargo-", ""); | ||||||
let arguments: Vec<String> = std::env::args() | ||||||
.skip( | ||||||
if std::env::args().nth(1).unwrap_or_else(|| "".to_string()) == name { | ||||||
2 | ||||||
} else { | ||||||
1 | ||||||
}, | ||||||
) | ||||||
.collect(); | ||||||
|
||||||
println!( | ||||||
"{}: the command `cargo {}` may be deprecated, please use `cargo all-features build`", | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||
Paint::yellow("warning").bold(), | ||||||
name | ||||||
); | ||||||
|
||||||
if let Err(error) = run_main(command, &arguments, None, CommandTarget::Cargo) { | ||||||
println!("{}: {}", Paint::red("error").bold(), error); | ||||||
} | ||||||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
pub mod deprecated_glue; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
tarpaulin
is a code coverage reporting tool, and seems like not a unused dependencies analyzer:There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sry, yes totally missed that copy paste error, thanks