Skip to content

Commit c7cdf23

Browse files
[clap-v3-utils] Remove deprecated functions (pyth-network#313)
* add `deprecated` feature to produce warnings on use of deprecated functions * replace `multiple_occurrences` with arg actions * replace `possible_values` with `PossibleValueParser` * deprecated `value_of` and `values_of` * deprecate `unix_timestamp_from_rfc3339_datetime` * deprecate `cluster_type_of` * deprecate `commitment_of` * deprecate `keypair_of`, `keypairs_of`, `pubkey_of`, and `pubkeys_of` functions * replace deprecated functions from `try_keypair_of`, `try_keypairs_of`, `try_pubkey_of`, and `try_pubkeys_of` * deprecate `pubkeys_sigs_of` * allow deprecated on tests * remove `deprecation` feature from clap-v3-utils * re-export `pubkeys_sigs_of` * add helper `extract_keypair` to dedupe `try_keypair_of` and `try_keypairs_of` * remove unwraps and expects * bump deprecation version
1 parent e963f87 commit c7cdf23

File tree

5 files changed

+202
-25
lines changed

5 files changed

+202
-25
lines changed

clap-v3-utils/src/input_parsers/mod.rs

Lines changed: 134 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -21,12 +21,18 @@ pub mod signer;
2121
since = "1.17.0",
2222
note = "Please use the functions in `solana_clap_v3_utils::input_parsers::signer` directly instead"
2323
)]
24+
#[allow(deprecated)]
2425
pub use signer::{
2526
pubkey_of_signer, pubkeys_of_multiple_signers, pubkeys_sigs_of, resolve_signer, signer_of,
2627
STDOUT_OUTFILE_TOKEN,
2728
};
2829

2930
// Return parsed values from matches at `name`
31+
#[deprecated(
32+
since = "2.0.0",
33+
note = "Please use the functions `ArgMatches::get_many` or `ArgMatches::try_get_many` instead"
34+
)]
35+
#[allow(deprecated)]
3036
pub fn values_of<T>(matches: &ArgMatches, name: &str) -> Option<Vec<T>>
3137
where
3238
T: std::str::FromStr,
@@ -38,6 +44,11 @@ where
3844
}
3945

4046
// Return a parsed value from matches at `name`
47+
#[deprecated(
48+
since = "2.0.0",
49+
note = "Please use the functions `ArgMatches::get_one` or `ArgMatches::try_get_one` instead"
50+
)]
51+
#[allow(deprecated)]
4152
pub fn value_of<T>(matches: &ArgMatches, name: &str) -> Option<T>
4253
where
4354
T: std::str::FromStr,
@@ -48,6 +59,11 @@ where
4859
.and_then(|value| value.parse::<T>().ok())
4960
}
5061

62+
#[deprecated(
63+
since = "2.0.0",
64+
note = "Please use `ArgMatches::get_one::<UnixTimestamp>(...)` instead"
65+
)]
66+
#[allow(deprecated)]
5167
pub fn unix_timestamp_from_rfc3339_datetime(
5268
matches: &ArgMatches,
5369
name: &str,
@@ -63,14 +79,25 @@ pub fn unix_timestamp_from_rfc3339_datetime(
6379
since = "1.17.0",
6480
note = "please use `Amount::parse_decimal` and `Amount::sol_to_lamport` instead"
6581
)]
82+
#[allow(deprecated)]
6683
pub fn lamports_of_sol(matches: &ArgMatches, name: &str) -> Option<u64> {
6784
value_of(matches, name).map(sol_to_lamports)
6885
}
6986

87+
#[deprecated(
88+
since = "2.0.0",
89+
note = "Please use `ArgMatches::get_one::<ClusterType>(...)` instead"
90+
)]
91+
#[allow(deprecated)]
7092
pub fn cluster_type_of(matches: &ArgMatches, name: &str) -> Option<ClusterType> {
7193
value_of(matches, name)
7294
}
7395

96+
#[deprecated(
97+
since = "2.0.0",
98+
note = "Please use `ArgMatches::get_one::<CommitmentConfig>(...)` instead"
99+
)]
100+
#[allow(deprecated)]
74101
pub fn commitment_of(matches: &ArgMatches, name: &str) -> Option<CommitmentConfig> {
75102
matches
76103
.value_of(name)
@@ -246,6 +273,11 @@ pub fn parse_derived_address_seed(arg: &str) -> Result<String, String> {
246273
}
247274

248275
// Return the keypair for an argument with filename `name` or None if not present.
276+
#[deprecated(
277+
since = "2.0.0",
278+
note = "Please use `input_parsers::signer::try_keypair_of` instead"
279+
)]
280+
#[allow(deprecated)]
249281
pub fn keypair_of(matches: &ArgMatches, name: &str) -> Option<Keypair> {
250282
if let Some(value) = matches.value_of(name) {
251283
if value == ASK_KEYWORD {
@@ -259,6 +291,11 @@ pub fn keypair_of(matches: &ArgMatches, name: &str) -> Option<Keypair> {
259291
}
260292
}
261293

294+
#[deprecated(
295+
since = "2.0.0",
296+
note = "Please use `input_parsers::signer::try_keypairs_of` instead"
297+
)]
298+
#[allow(deprecated)]
262299
pub fn keypairs_of(matches: &ArgMatches, name: &str) -> Option<Vec<Keypair>> {
263300
matches.values_of(name).map(|values| {
264301
values
@@ -276,10 +313,20 @@ pub fn keypairs_of(matches: &ArgMatches, name: &str) -> Option<Vec<Keypair>> {
276313

277314
// Return a pubkey for an argument that can itself be parsed into a pubkey,
278315
// or is a filename that can be read as a keypair
316+
#[deprecated(
317+
since = "2.0.0",
318+
note = "Please use `input_parsers::signer::try_pubkey_of` instead"
319+
)]
320+
#[allow(deprecated)]
279321
pub fn pubkey_of(matches: &ArgMatches, name: &str) -> Option<Pubkey> {
280322
value_of(matches, name).or_else(|| keypair_of(matches, name).map(|keypair| keypair.pubkey()))
281323
}
282324

325+
#[deprecated(
326+
since = "2.0.0",
327+
note = "Please use `input_parsers::signer::try_pubkeys_of` instead"
328+
)]
329+
#[allow(deprecated)]
283330
pub fn pubkeys_of(matches: &ArgMatches, name: &str) -> Option<Vec<Pubkey>> {
284331
matches.values_of(name).map(|values| {
285332
values
@@ -294,12 +341,13 @@ pub fn pubkeys_of(matches: &ArgMatches, name: &str) -> Option<Vec<Pubkey>> {
294341
})
295342
}
296343

344+
#[allow(deprecated)]
297345
#[cfg(test)]
298346
mod tests {
299347
use {
300348
super::*,
301-
clap::{Arg, Command},
302-
solana_sdk::{hash::Hash, pubkey::Pubkey},
349+
clap::{Arg, ArgAction, Command},
350+
solana_sdk::{commitment_config::CommitmentLevel, hash::Hash, pubkey::Pubkey},
303351
};
304352

305353
fn app<'ab>() -> Command<'ab> {
@@ -308,7 +356,7 @@ mod tests {
308356
Arg::new("multiple")
309357
.long("multiple")
310358
.takes_value(true)
311-
.multiple_occurrences(true)
359+
.action(ArgAction::Append)
312360
.multiple_values(true),
313361
)
314362
.arg(Arg::new("single").takes_value(true).long("single"))
@@ -545,4 +593,87 @@ mod tests {
545593
}
546594
}
547595
}
596+
597+
#[test]
598+
fn test_unix_timestamp_from_rfc3339_datetime() {
599+
let command = Command::new("test").arg(
600+
Arg::new("timestamp")
601+
.long("timestamp")
602+
.takes_value(true)
603+
.value_parser(clap::value_parser!(UnixTimestamp)),
604+
);
605+
606+
// success case
607+
let matches = command
608+
.clone()
609+
.try_get_matches_from(vec!["test", "--timestamp", "1234"])
610+
.unwrap();
611+
assert_eq!(
612+
*matches.get_one::<UnixTimestamp>("timestamp").unwrap(),
613+
1234,
614+
);
615+
616+
// validation fails
617+
let matches_error = command
618+
.clone()
619+
.try_get_matches_from(vec!["test", "--timestamp", "this_is_an_invalid_arg"])
620+
.unwrap_err();
621+
assert_eq!(matches_error.kind, clap::error::ErrorKind::ValueValidation);
622+
}
623+
624+
#[test]
625+
fn test_cluster_type() {
626+
let command = Command::new("test").arg(
627+
Arg::new("cluster")
628+
.long("cluster")
629+
.takes_value(true)
630+
.value_parser(clap::value_parser!(ClusterType)),
631+
);
632+
633+
// success case
634+
let matches = command
635+
.clone()
636+
.try_get_matches_from(vec!["test", "--cluster", "testnet"])
637+
.unwrap();
638+
assert_eq!(
639+
*matches.get_one::<ClusterType>("cluster").unwrap(),
640+
ClusterType::Testnet
641+
);
642+
643+
// validation fails
644+
let matches_error = command
645+
.clone()
646+
.try_get_matches_from(vec!["test", "--cluster", "this_is_an_invalid_arg"])
647+
.unwrap_err();
648+
assert_eq!(matches_error.kind, clap::error::ErrorKind::ValueValidation);
649+
}
650+
651+
#[test]
652+
fn test_commitment_config() {
653+
let command = Command::new("test").arg(
654+
Arg::new("commitment")
655+
.long("commitment")
656+
.takes_value(true)
657+
.value_parser(clap::value_parser!(CommitmentConfig)),
658+
);
659+
660+
// success case
661+
let matches = command
662+
.clone()
663+
.try_get_matches_from(vec!["test", "--commitment", "finalized"])
664+
.unwrap();
665+
assert_eq!(
666+
*matches.get_one::<CommitmentConfig>("commitment").unwrap(),
667+
CommitmentConfig {
668+
commitment: CommitmentLevel::Finalized
669+
},
670+
);
671+
672+
// validation fails
673+
let matches_error = command
674+
.clone()
675+
.try_get_matches_from(vec!["test", "--commitment", "this_is_an_invalid_arg"])
676+
.unwrap_err();
677+
assert_eq!(matches_error.kind, clap::error::ErrorKind::ValueValidation);
678+
}
548679
}

clap-v3-utils/src/input_parsers/signer.rs

Lines changed: 61 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
use {
2-
crate::{
3-
input_parsers::{keypair_of, keypairs_of, pubkey_of, pubkeys_of},
4-
keypair::{pubkey_from_path, resolve_signer_from_path, signer_from_path, ASK_KEYWORD},
2+
crate::keypair::{
3+
keypair_from_seed_phrase, pubkey_from_path, resolve_signer_from_path, signer_from_path,
4+
ASK_KEYWORD, SKIP_SEED_PHRASE_VALIDATION_ARG,
55
},
66
clap::{builder::ValueParser, ArgMatches},
77
solana_remote_wallet::{
@@ -11,7 +11,7 @@ use {
1111
solana_sdk::{
1212
derivation_path::{DerivationPath, DerivationPathError},
1313
pubkey::Pubkey,
14-
signature::{Keypair, Signature, Signer},
14+
signature::{read_keypair_file, Keypair, Signature, Signer},
1515
},
1616
std::{error, rc::Rc, str::FromStr},
1717
thiserror::Error,
@@ -236,16 +236,35 @@ pub fn try_keypair_of(
236236
matches: &ArgMatches,
237237
name: &str,
238238
) -> Result<Option<Keypair>, Box<dyn error::Error>> {
239-
matches.try_contains_id(name)?;
240-
Ok(keypair_of(matches, name))
239+
if let Some(value) = matches.try_get_one::<String>(name)? {
240+
extract_keypair(matches, name, value)
241+
} else {
242+
Ok(None)
243+
}
241244
}
242245

243246
pub fn try_keypairs_of(
244247
matches: &ArgMatches,
245248
name: &str,
246249
) -> Result<Option<Vec<Keypair>>, Box<dyn error::Error>> {
247-
matches.try_contains_id(name)?;
248-
Ok(keypairs_of(matches, name))
250+
Ok(matches.try_get_many::<String>(name)?.map(|values| {
251+
values
252+
.filter_map(|value| extract_keypair(matches, name, value).ok().flatten())
253+
.collect()
254+
}))
255+
}
256+
257+
fn extract_keypair(
258+
matches: &ArgMatches,
259+
name: &str,
260+
path: &str,
261+
) -> Result<Option<Keypair>, Box<dyn error::Error>> {
262+
if path == ASK_KEYWORD {
263+
let skip_validation = matches.try_contains_id(SKIP_SEED_PHRASE_VALIDATION_ARG.name)?;
264+
keypair_from_seed_phrase(name, skip_validation, true, None, true).map(Some)
265+
} else {
266+
read_keypair_file(path).map(Some)
267+
}
249268
}
250269

251270
// Return a `Result` wrapped pubkey for an argument that can itself be parsed into a pubkey,
@@ -254,19 +273,31 @@ pub fn try_pubkey_of(
254273
matches: &ArgMatches,
255274
name: &str,
256275
) -> Result<Option<Pubkey>, Box<dyn error::Error>> {
257-
matches.try_contains_id(name)?;
258-
Ok(pubkey_of(matches, name))
276+
if let Some(pubkey) = matches.try_get_one::<Pubkey>(name)? {
277+
Ok(Some(*pubkey))
278+
} else {
279+
Ok(try_keypair_of(matches, name)?.map(|keypair| keypair.pubkey()))
280+
}
259281
}
260282

261283
pub fn try_pubkeys_of(
262284
matches: &ArgMatches,
263285
name: &str,
264286
) -> Result<Option<Vec<Pubkey>>, Box<dyn error::Error>> {
265-
matches.try_contains_id(name)?;
266-
Ok(pubkeys_of(matches, name))
287+
if let Some(pubkey_strings) = matches.try_get_many::<String>(name)? {
288+
let mut pubkeys = Vec::with_capacity(pubkey_strings.len());
289+
for pubkey_string in pubkey_strings {
290+
pubkeys.push(pubkey_string.parse::<Pubkey>()?);
291+
}
292+
Ok(Some(pubkeys))
293+
} else {
294+
Ok(None)
295+
}
267296
}
268297

269298
// Return pubkey/signature pairs for a string of the form pubkey=signature
299+
#[deprecated(since = "2.0.0", note = "Please use `try_pubkeys_sigs_of` instead")]
300+
#[allow(deprecated)]
270301
pub fn pubkeys_sigs_of(matches: &ArgMatches, name: &str) -> Option<Vec<(Pubkey, Signature)>> {
271302
matches.values_of(name).map(|values| {
272303
values
@@ -286,8 +317,20 @@ pub fn try_pubkeys_sigs_of(
286317
matches: &ArgMatches,
287318
name: &str,
288319
) -> Result<Option<Vec<(Pubkey, Signature)>>, Box<dyn error::Error>> {
289-
matches.try_contains_id(name)?;
290-
Ok(pubkeys_sigs_of(matches, name))
320+
if let Some(pubkey_signer_strings) = matches.try_get_many::<String>(name)? {
321+
let mut pubkey_sig_pairs = Vec::with_capacity(pubkey_signer_strings.len());
322+
for pubkey_signer_string in pubkey_signer_strings {
323+
let (pubkey_string, sig_string) = pubkey_signer_string
324+
.split_once('=')
325+
.ok_or("failed to parse `pubkey=signature` pair")?;
326+
let pubkey = Pubkey::from_str(pubkey_string)?;
327+
let sig = Signature::from_str(sig_string)?;
328+
pubkey_sig_pairs.push((pubkey, sig));
329+
}
330+
Ok(Some(pubkey_sig_pairs))
331+
} else {
332+
Ok(None)
333+
}
291334
}
292335

293336
// Return a signer from matches at `name`
@@ -376,12 +419,14 @@ impl FromStr for PubkeySignature {
376419
}
377420
}
378421

422+
#[allow(deprecated)]
379423
#[cfg(test)]
380424
mod tests {
381425
use {
382426
super::*,
427+
crate::input_parsers::{keypair_of, pubkey_of, pubkeys_of},
383428
assert_matches::assert_matches,
384-
clap::{Arg, Command},
429+
clap::{Arg, ArgAction, Command},
385430
solana_remote_wallet::locator::Manufacturer,
386431
solana_sdk::signature::write_keypair_file,
387432
std::fs,
@@ -512,7 +557,7 @@ mod tests {
512557
Arg::new("multiple")
513558
.long("multiple")
514559
.takes_value(true)
515-
.multiple_occurrences(true)
560+
.action(ArgAction::Append)
516561
.multiple_values(true),
517562
)
518563
.arg(Arg::new("single").takes_value(true).long("single"))

0 commit comments

Comments
 (0)