Skip to content

Commit

Permalink
Merge pull request #92 from pacak/master
Browse files Browse the repository at this point in the history
Upgrade bpaf to 0.7 to remove some turbofishes
  • Loading branch information
Shnatsel committed Nov 3, 2022
2 parents 29bfcb2 + dcbfb61 commit 4830980
Show file tree
Hide file tree
Showing 13 changed files with 280 additions and 245 deletions.
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

0 comments on commit 4830980

Please sign in to comment.