Skip to content
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

Upgrade bpaf to 0.7 to remove some turbofishes #92

Merged
merged 4 commits into from
Nov 3, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
64 changes: 62 additions & 2 deletions Cargo.lock

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

6 changes: 5 additions & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,12 @@ serde = { version = "1.0", features = ["derive"] }
serde_json = "1.0"
tar = "0.4.30"
indicatif = "0.17.0"
bpaf = "0.6.0"
bpaf = { version = "0.7.0", features = ["derive"] }
anyhow = "1.0.28"

[dev-dependencies]
schemars = "0.8.3"

[features]
bright-color = ["bpaf/bright-color"]
dull-color = ["bpaf/dull-color"]
8 changes: 8 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,14 @@ Most commands also accept flags controlling the features, targets, etc.
See 'cargo supply-chain <command> --help' for more information on a specific command.
```

## Colorful line parser output

You can install `cargo-supply-chain` with one of two features to get prettier command line
```console
cargo install cargo-supply-chain -F bright-color
cargo install cargo-supply-chain -F dull-color
```

## License

Triple licensed under any of Apache-2.0, MIT, or zlib terms.
2 changes: 1 addition & 1 deletion src/api_client.rs
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ impl RateLimitedClient {
}

/// Waits until at least 1 second has elapsed since last request,
/// as per https://crates.io/data-access
/// as per <https://crates.io/data-access>
fn wait_to_honor_rate_limit(&mut self) {
if let Some(prev_req_time) = self.last_request_time {
let next_req_time = prev_req_time + Duration::from_secs(1);
Expand Down
210 changes: 91 additions & 119 deletions src/cli.rs
Original file line number Diff line number Diff line change
@@ -1,30 +1,113 @@
use crate::common::MetadataArgs;
use bpaf::*;
use std::{path::PathBuf, time::Duration};

/// Arguments to be passed to `cargo metadata`
#[derive(Clone, Debug, Bpaf)]
#[bpaf(generate(meta_args))]
pub struct MetadataArgs {
// `all_features` and `no_default_features` are not mutually exclusive in `cargo metadata`,
// in the sense that it will not error out when encontering them; it just follows `all_features`
/// Activate all available features
pub all_features: bool,

/// Do not activate the `default` feature
pub no_default_features: bool,

// This is a `String` because we don't parse the value, just pass it on to `cargo metadata` blindly
/// Space or comma separated list of features to activate
#[bpaf(argument("FEATURES"))]
pub features: Option<String>,

/// Only include dependencies matching the given target-triple
#[bpaf(argument("TRIPLE"))]
pub target: Option<String>,

/// Path to Cargo.toml
#[bpaf(argument("PATH"))]
pub manifest_path: Option<PathBuf>,
}

/// Arguments for typical querying commands - crates, publishers, json
#[derive(Clone, Debug)]
#[derive(Clone, Debug, Bpaf)]
#[bpaf(generate(args))]
pub(crate) struct QueryCommandArgs {
#[bpaf(external)]
pub cache_max_age: Duration,

/// Make output more friendly towards tools such as `diff`
#[bpaf(short, long)]
pub diffable: bool,
}

#[derive(Clone, Debug)]
pub(crate) enum CliArgs {
Publishers {
#[derive(Clone, Debug, Bpaf)]
pub(crate) enum PrintJson {
/// Print JSON schema and exit
#[bpaf(long("print-schema"))]
Schema,

Info {
#[bpaf(external)]
args: QueryCommandArgs,
#[bpaf(external)]
meta_args: MetadataArgs,
},
Crates {
}

/// Gather author, contributor and publisher data on crates in your dependency graph
///
///
/// Most commands also accept flags controlling the features, targets, etc.
/// See 'cargo supply-chain <command> --help' for more information on a specific command.
#[derive(Clone, Debug, Bpaf)]
#[bpaf(options("supply-chain"), generate(args_parser), version)]
pub(crate) enum CliArgs {
/// Lists all crates.io publishers in the dependency graph and owned crates for each
///
///
/// If a local cache created by 'update' subcommand is present and up to date,
/// it will be used. Otherwise live data will be fetched from the crates.io API.
#[bpaf(command)]
Publishers {
#[bpaf(external)]
args: QueryCommandArgs,
#[bpaf(external)]
meta_args: MetadataArgs,
},
Json {

/// List all crates in dependency graph and crates.io publishers for each
///
///
/// If a local cache created by 'update' subcommand is present and up to date,
/// it will be used. Otherwise live data will be fetched from the crates.io API.
#[bpaf(command)]
Crates {
#[bpaf(external)]
args: QueryCommandArgs,
#[bpaf(external)]
meta_args: MetadataArgs,
},
JsonSchema,

/// Detailed info on publishers of all crates in the dependency graph, in JSON
///
/// The JSON schema is also available, use --print-schema to get it.
///
/// If a local cache created by 'update' subcommand is present and up to date,
/// it will be used. Otherwise live data will be fetched from the crates.io API.",
#[bpaf(command)]
Json(#[bpaf(external(print_json))] PrintJson),

/// Download the latest daily dump from crates.io to speed up other commands
///
///
/// If the local cache is already younger than specified in '--cache-max-age' option,
/// a newer version will not be downloaded.
///
/// Note that this downloads the entire crates.io database, which is hundreds of Mb of data!
/// If you are on a metered connection, you should not be running the 'update' subcommand.
/// Instead, rely on requests to the live API - they are slower, but use much less data.
#[bpaf(command)]
Update {
#[bpaf(external)]
cache_max_age: Duration,
},
}
Expand All @@ -42,117 +125,6 @@ If not specified, the cache is considered valid for 48 hours.",
.fallback(Duration::from_secs(48 * 3600))
}

fn args() -> impl Parser<QueryCommandArgs> {
let diffable = short('d')
.long("diffable")
.help("Make output more friendly towards tools such as `diff`")
.switch();
construct!(QueryCommandArgs {
cache_max_age(),
diffable,
})
}

fn meta_args() -> impl Parser<MetadataArgs> {
let all_features = long("all-features")
.help("Activate all available features")
.switch();
let no_default_features = long("no-default-features")
.help("Do not activate the `default` feature")
.switch();
let features = long("features")
.help("Space or comma separated list of features to activate")
.argument::<String>("FEATURES")
.optional();
let target = long("target")
.help("Only include dependencies matching the given target-triple")
.argument::<String>("TRIPLE")
.optional();
let manifest_path = long("manifest-path")
.help("Path to Cargo.toml")
.argument::<PathBuf>("PATH")
.map(PathBuf::from)
.optional();
construct!(MetadataArgs {
all_features,
no_default_features,
features,
target,
manifest_path,
})
}

pub(crate) fn args_parser() -> OptionParser<CliArgs> {
let publishers = construct!(CliArgs::Publishers { args(), meta_args() })
.to_options()
.descr("Lists all crates.io publishers in the dependency graph and owned crates for each")
.header(
"\
If a local cache created by 'update' subcommand is present and up to date,
it will be used. Otherwise live data will be fetched from the crates.io API.",
)
.command("publishers");

let crates = (construct!(CliArgs::Crates { args(), meta_args() }))
.to_options()
.descr("List all crates in dependency graph and crates.io publishers for each")
.header(
"\
If a local cache created by 'update' subcommand is present and up to date,
it will be used. Otherwise live data will be fetched from the crates.io API.",
)
.command("crates");

let json = {
let print_schema = long("print-schema")
.help("Print JSON schema and exit")
.req_flag(CliArgs::JsonSchema);
let json = construct!(CliArgs::Json { args(), meta_args() });
(construct!([json, print_schema]))
.to_options()
.descr(
"\
Detailed info on publishers of all crates in the dependency graph, in JSON
The JSON schema is also available, use --print-schema to get it.
If a local cache created by 'update' subcommand is present and up to date,
it will be used. Otherwise live data will be fetched from the crates.io API.",
)
.command("json")
.help("Like 'crates', but in JSON and with more fields for each publisher")
};

let update = construct!(CliArgs::Update { cache_max_age() })
.to_options()
.descr(
"\
Download the latest daily dump from crates.io to speed up other commands
If the local cache is already younger than specified in '--cache-max-age' option,
a newer version will not be downloaded.
Note that this downloads the entire crates.io database, which is hundreds of Mb of data!
If you are on a metered connection, you should not be running the 'update' subcommand.
Instead, rely on requests to the live API - they are slower, but use much less data.",
)
.command("update")
.help("Download the latest daily dump from crates.io to speed up other commands");

cargo_helper(
"supply-chain",
construct!([publishers, crates, json, update]),
)
.to_options()
.version(env!("CARGO_PKG_VERSION"))
.descr("Gather author, contributor and publisher data on crates in your dependency graph")
.footer(
"\
Most commands also accept flags controlling the features, targets, etc.
See 'cargo supply-chain <command> --help' for more information on a specific command.",
)
}

#[cfg(test)]
mod tests {
use super::*;
Expand Down