Skip to content

Commit

Permalink
feat: split into junks
Browse files Browse the repository at this point in the history
  • Loading branch information
somehowchris committed Apr 16, 2022
1 parent d6d6cc3 commit 9dbb321
Show file tree
Hide file tree
Showing 16 changed files with 735 additions and 381 deletions.
8 changes: 7 additions & 1 deletion Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 2 additions & 2 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -27,11 +27,11 @@ path = "src/bin/cargo-all-features.rs"

[dependencies]
itertools = "0.10.3"
termcolor = "1.1.3"
serde_json = "1.0.79"
serde = { version = "1.0.136", features = ["derive"] }
rayon = "1.5.2"
validator = { version = "0.14.0", features = ["derive"] }
lazy_static = "1.4.0"
which = "4.2.5"
clap = { version = "3.1.9", features = ["derive"] }
clap = { version = "3.1.9", features = ["derive", "cargo"] }
yansi = "0.5.1"
77 changes: 72 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,21 +17,88 @@ 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
- 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`
</details>

## Why?

Expand Down Expand Up @@ -69,8 +136,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.

Expand Down
79 changes: 60 additions & 19 deletions src/bin/cargo-all-features.rs
Original file line number Diff line number Diff line change
@@ -1,14 +1,35 @@
use cargo_all_features::runner::CargoCommand;
use clap::{Parser, Subcommand};
use termcolor::{Color, ColorChoice, ColorSpec, StandardStream, WriteColor};
use cargo_all_features::{runner::CargoCommand, 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)]
pub chunks: Option<u8>,
#[clap(long, help="The total number of chunks to split into. Only used for calculations", possible_values(["1.."]))]
pub chunks: Option<usize>,

#[clap(long)]
pub chunk: Option<u8>,
#[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,
Expand All @@ -23,21 +44,19 @@ enum FlagsAndOptions {
External(Vec<String>),
}

fn run_command(command: CargoCommand, args: &[String]) {
if let Err(error) = cargo_all_features::run(command, args) {
let mut stdout = StandardStream::stdout(ColorChoice::Auto);
stdout
.set_color(ColorSpec::new().set_fg(Some(Color::Red)).set_bold(true))
.unwrap();
print!("error");
stdout.reset().unwrap();

println!(": {}", error);
// Runs the command and prints out in rust known error format
fn run_command(command: CargoCommand, args: &[String], options: Option<Options>) {
if let Err(error) = cargo_all_features::run(command, args, options) {
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
Expand All @@ -46,15 +65,37 @@ pub fn main() {
},
);

// 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();
}

// 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);
run_command(args.command, &commands, Some(options));
}
}
} else {
run_command(args.command, &[]);
run_command(args.command, &[], Some(options));
}
}
23 changes: 6 additions & 17 deletions src/bin/common/deprecated_glue.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
use cargo_all_features::{run as run_main, runner::CargoCommand};
use termcolor::{Color, ColorChoice, ColorSpec, StandardStream, WriteColor};
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()
Expand All @@ -13,25 +14,13 @@ pub fn run(command: CargoCommand) {
)
.collect();

let mut stdout = StandardStream::stdout(ColorChoice::Auto);
stdout
.set_color(ColorSpec::new().set_fg(Some(Color::Yellow)).set_bold(true))
.unwrap();
print!("warning");
stdout.reset().unwrap();
println!(
": the command `cargo {}` may be deprecated, please use `cargo all-features build`",
"{}: the command `cargo {}` may be deprecated, please use `cargo all-features build`",
Paint::yellow("warning").bold(),
name
);

if let Err(error) = run_main(command, &arguments) {
let mut stdout = StandardStream::stdout(ColorChoice::Auto);
stdout
.set_color(ColorSpec::new().set_fg(Some(Color::Red)).set_bold(true))
.unwrap();
print!("error");
stdout.reset().unwrap();

println!(": {}", error);
if let Err(error) = run_main(command, &arguments, None) {
println!("{}: {}", Paint::red("error").bold(), error);
}
}
55 changes: 55 additions & 0 deletions src/constants.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
use crate::CargoCommand;
use crate::CargoCommandOrigin;
use rayon::prelude::*;
use std::collections::HashMap;

/// Static list of flags not allowed because they can interfere with the commands initiated by this crate
pub const FORBIDDEN_FLAGS: [&str; 20] = [
"--no-default-features",
"--features",
"--bin",
"--lib",
"-p",
"--bins",
"--workspace",
"--example",
"--examples",
"--test",
"--tests",
"--bench",
"--benches",
"--all-targets",
"--manifest-path",
"--all",
"--exclude",
"--bins",
"--libs",
"--color",
];

lazy_static::lazy_static! {
/// Static table of commands and their origin
/// This is needed to make sure commands are installed
pub static ref COMMAND_ORIGIN_LOOKUP_MAP: HashMap<CargoCommand, CargoCommandOrigin> = [
(CargoCommand::Build, CargoCommandOrigin::FirstParty),
(CargoCommand::Check, CargoCommandOrigin::FirstParty),
(CargoCommand::Test, CargoCommandOrigin::FirstParty),
(CargoCommand::Bench, CargoCommandOrigin::FirstParty),
(CargoCommand::MiriTest, CargoCommandOrigin::RustUpComponent {
name: "miri",
help_url: "https://github.com/rust-lang/miri"
}),
(CargoCommand::Udeps, CargoCommandOrigin::ThirdPartyCrate {
name: "cargo-udeps",
help_url: "https://github.com/est31/cargo-udeps"
}),
(CargoCommand::Tarpaulin, CargoCommandOrigin::ThirdPartyCrate {
name: "cargo-tarpaulin",
help_url: "https://github.com/xd009642/tarpaulin"
}),
(CargoCommand::Nextest, CargoCommandOrigin::ThirdPartyCrate {
name: "cargo-nextest",
help_url: "https://github.com/nextest-rs/nextest"
}),
].par_iter().copied().collect();
}
Loading

0 comments on commit 9dbb321

Please sign in to comment.