Skip to content

Commit

Permalink
feat: add global --json flag (#9244)
Browse files Browse the repository at this point in the history
* add global json --flag

* finish port to shell::is_json

* fix test

* update message

* very strange stalling bug, fixed by assignment?

* remove jobs -j shorthand clashing with global json flag

* fix test after -j change

* fix doctests

* temporarily disable junit conflict, revert -j as --json shorthand

* tag --color, --quiet as conflicting with --json

* update tests to be aware of global args to avoid `Argument or group quiet specified in conflicts_with* for junit does not exist` error

* fix missed test

* make sure tests throw on non-matching command

* use --format-json in command to show alias works
  • Loading branch information
zerosnacks authored Nov 4, 2024
1 parent 931374b commit e2a6282
Show file tree
Hide file tree
Showing 21 changed files with 192 additions and 208 deletions.
28 changes: 0 additions & 28 deletions crates/cast/bin/args.rs
Original file line number Diff line number Diff line change
Expand Up @@ -369,10 +369,6 @@ pub enum CastSubcommand {
#[arg(long, env = "CAST_FULL_BLOCK")]
full: bool,

/// Print the block as JSON.
#[arg(long, short, help_heading = "Display options")]
json: bool,

#[command(flatten)]
rpc: RpcOpts,
},
Expand Down Expand Up @@ -464,10 +460,6 @@ pub enum CastSubcommand {
#[arg(long, conflicts_with = "field")]
raw: bool,

/// Print as JSON.
#[arg(long, short, help_heading = "Display options")]
json: bool,

#[command(flatten)]
rpc: RpcOpts,
},
Expand All @@ -489,10 +481,6 @@ pub enum CastSubcommand {
#[arg(id = "async", long = "async", env = "CAST_ASYNC", alias = "cast-async")]
cast_async: bool,

/// Print as JSON.
#[arg(long, short, help_heading = "Display options")]
json: bool,

#[command(flatten)]
rpc: RpcOpts,
},
Expand Down Expand Up @@ -530,10 +518,6 @@ pub enum CastSubcommand {

/// The ABI-encoded calldata.
calldata: String,

/// Print the decoded calldata as JSON.
#[arg(long, short, help_heading = "Display options")]
json: bool,
},

/// Decode ABI-encoded string.
Expand All @@ -543,10 +527,6 @@ pub enum CastSubcommand {
StringDecode {
/// The ABI-encoded string.
data: String,

/// Print the decoded string as JSON.
#[arg(long, short, help_heading = "Display options")]
json: bool,
},

/// Decode ABI-encoded input or output data.
Expand All @@ -565,10 +545,6 @@ pub enum CastSubcommand {
/// Whether to decode the input or output data.
#[arg(long, short, help_heading = "Decode input data instead of output data")]
input: bool,

/// Print the decoded calldata as JSON.
#[arg(long, short, help_heading = "Display options")]
json: bool,
},

/// ABI encode the given function argument, excluding the selector.
Expand Down Expand Up @@ -655,10 +631,6 @@ pub enum CastSubcommand {
FourByteDecode {
/// The ABI-encoded calldata.
calldata: Option<String>,

/// Print the decoded calldata as JSON.
#[arg(long, short, help_heading = "Display options")]
json: bool,
},

/// Get the event signature for a given topic 0 from https://openchain.xyz.
Expand Down
8 changes: 2 additions & 6 deletions crates/cast/bin/cmd/access_list.rs
Original file line number Diff line number Diff line change
Expand Up @@ -35,10 +35,6 @@ pub struct AccessListArgs {
#[arg(long, short = 'B')]
block: Option<BlockId>,

/// Print the access list as JSON.
#[arg(long, short, help_heading = "Display options")]
json: bool,

#[command(flatten)]
tx: TransactionOpts,

Expand All @@ -48,7 +44,7 @@ pub struct AccessListArgs {

impl AccessListArgs {
pub async fn run(self) -> Result<()> {
let Self { to, sig, args, tx, eth, block, json: to_json } = self;
let Self { to, sig, args, tx, eth, block } = self;

let config = Config::from(&eth);
let provider = utils::get_provider(&config)?;
Expand All @@ -65,7 +61,7 @@ impl AccessListArgs {

let cast = Cast::new(&provider);

let access_list: String = cast.access_list(&tx, block, to_json).await?;
let access_list: String = cast.access_list(&tx, block).await?;

sh_println!("{access_list}")?;

Expand Down
7 changes: 1 addition & 6 deletions crates/cast/bin/cmd/call.rs
Original file line number Diff line number Diff line change
Expand Up @@ -69,10 +69,6 @@ pub struct CallArgs {
#[arg(long, short)]
block: Option<BlockId>,

/// Print the decoded output as JSON.
#[arg(long, short, help_heading = "Display options")]
json: bool,

/// Enable Alphanet features.
#[arg(long, alias = "odyssey")]
pub alphanet: bool,
Expand Down Expand Up @@ -131,7 +127,6 @@ impl CallArgs {
decode_internal,
labels,
data,
json,
..
} = self;

Expand Down Expand Up @@ -205,7 +200,7 @@ impl CallArgs {
return Ok(());
}

sh_println!("{}", Cast::new(provider).call(&tx, func.as_ref(), block, json).await?)?;
sh_println!("{}", Cast::new(provider).call(&tx, func.as_ref(), block).await?)?;

Ok(())
}
Expand Down
10 changes: 3 additions & 7 deletions crates/cast/bin/cmd/interface.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ use clap::Parser;
use eyre::{Context, Result};
use foundry_block_explorers::Client;
use foundry_cli::opts::EtherscanOpts;
use foundry_common::{compile::ProjectCompiler, fs};
use foundry_common::{compile::ProjectCompiler, fs, shell};
use foundry_compilers::{info::ContractInfo, utils::canonicalize};
use foundry_config::{load_config_with_root, try_find_project_root, Config};
use itertools::Itertools;
Expand Down Expand Up @@ -44,17 +44,13 @@ pub struct InterfaceArgs {
)]
output: Option<PathBuf>,

/// If specified, the interface will be output as JSON rather than Solidity.
#[arg(long, short)]
json: bool,

#[command(flatten)]
etherscan: EtherscanOpts,
}

impl InterfaceArgs {
pub async fn run(self) -> Result<()> {
let Self { contract, name, pragma, output: output_location, etherscan, json } = self;
let Self { contract, name, pragma, output: output_location, etherscan } = self;

// Determine if the target contract is an ABI file, a local contract or an Ethereum address.
let abis = if Path::new(&contract).is_file() &&
Expand All @@ -75,7 +71,7 @@ impl InterfaceArgs {
let interfaces = get_interfaces(abis)?;

// Print result or write to file.
let res = if json {
let res = if shell::is_json() {
// Format as JSON.
interfaces.iter().map(|iface| &iface.json_abi).format("\n").to_string()
} else {
Expand Down
20 changes: 4 additions & 16 deletions crates/cast/bin/cmd/logs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -49,26 +49,14 @@ pub struct LogsArgs {
#[arg(long)]
subscribe: bool,

/// Print the logs as JSON.s
#[arg(long, short, help_heading = "Display options")]
json: bool,

#[command(flatten)]
eth: EthereumOpts,
}

impl LogsArgs {
pub async fn run(self) -> Result<()> {
let Self {
from_block,
to_block,
address,
sig_or_topic,
topics_or_args,
subscribe,
json,
eth,
} = self;
let Self { from_block, to_block, address, sig_or_topic, topics_or_args, subscribe, eth } =
self;

let config = Config::from(&eth);
let provider = utils::get_provider(&config)?;
Expand All @@ -88,7 +76,7 @@ impl LogsArgs {
let filter = build_filter(from_block, to_block, address, sig_or_topic, topics_or_args)?;

if !subscribe {
let logs = cast.filter_logs(filter, json).await?;
let logs = cast.filter_logs(filter).await?;
sh_println!("{logs}")?;
return Ok(())
}
Expand All @@ -102,7 +90,7 @@ impl LogsArgs {
.await?;
let cast = Cast::new(&provider);
let mut stdout = io::stdout();
cast.subscribe(filter, &mut stdout, json).await?;
cast.subscribe(filter, &mut stdout).await?;

Ok(())
}
Expand Down
15 changes: 4 additions & 11 deletions crates/cast/bin/cmd/send.rs
Original file line number Diff line number Diff line change
Expand Up @@ -39,10 +39,6 @@ pub struct SendTxArgs {
#[arg(long, default_value = "1")]
confirmations: u64,

/// Print the transaction receipt as JSON.
#[arg(long, short, help_heading = "Display options")]
json: bool,

#[command(subcommand)]
command: Option<SendTxSubcommands>,

Expand Down Expand Up @@ -98,7 +94,6 @@ impl SendTxArgs {
mut args,
tx,
confirmations,
json: to_json,
command,
unlocked,
path,
Expand Down Expand Up @@ -159,7 +154,7 @@ impl SendTxArgs {

let (tx, _) = builder.build(config.sender).await?;

cast_send(provider, tx, cast_async, confirmations, timeout, to_json).await
cast_send(provider, tx, cast_async, confirmations, timeout).await
// Case 2:
// An option to use a local signer was provided.
// If we cannot successfully instantiate a local signer, then we will assume we don't have
Expand All @@ -178,7 +173,7 @@ impl SendTxArgs {
.wallet(wallet)
.on_provider(&provider);

cast_send(provider, tx, cast_async, confirmations, timeout, to_json).await
cast_send(provider, tx, cast_async, confirmations, timeout).await
}
}
}
Expand All @@ -189,7 +184,6 @@ async fn cast_send<P: Provider<T, AnyNetwork>, T: Transport + Clone>(
cast_async: bool,
confs: u64,
timeout: u64,
to_json: bool,
) -> Result<()> {
let cast = Cast::new(provider);
let pending_tx = cast.send(tx).await?;
Expand All @@ -199,9 +193,8 @@ async fn cast_send<P: Provider<T, AnyNetwork>, T: Transport + Clone>(
if cast_async {
sh_println!("{tx_hash:#x}")?;
} else {
let receipt = cast
.receipt(format!("{tx_hash:#x}"), None, confs, Some(timeout), false, to_json)
.await?;
let receipt =
cast.receipt(format!("{tx_hash:#x}"), None, confs, Some(timeout), false).await?;
sh_println!("{receipt}")?;
}

Expand Down
26 changes: 10 additions & 16 deletions crates/cast/bin/cmd/wallet/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ use cast::revm::primitives::Authorization;
use clap::Parser;
use eyre::{Context, Result};
use foundry_cli::{opts::RpcOpts, utils};
use foundry_common::{fs, sh_println};
use foundry_common::{fs, sh_println, shell};
use foundry_config::Config;
use foundry_wallets::{RawWalletOpts, WalletOpts, WalletSigner};
use rand::thread_rng;
Expand Down Expand Up @@ -49,10 +49,6 @@ pub enum WalletSubcommands {
/// Number of wallets to generate.
#[arg(long, short, default_value = "1")]
number: u32,

/// Output generated wallets as JSON.
#[arg(long, short, default_value = "false")]
json: bool,
},

/// Generates a random BIP39 mnemonic phrase
Expand All @@ -69,10 +65,6 @@ pub enum WalletSubcommands {
/// Entropy to use for the mnemonic
#[arg(long, short, conflicts_with = "words")]
entropy: Option<String>,

/// Output generated mnemonic phrase and accounts as JSON.
#[arg(long, short, default_value = "false")]
json: bool,
},

/// Generate a vanity address.
Expand Down Expand Up @@ -219,10 +211,10 @@ pub enum WalletSubcommands {
impl WalletSubcommands {
pub async fn run(self) -> Result<()> {
match self {
Self::New { path, unsafe_password, number, json, .. } => {
Self::New { path, unsafe_password, number, .. } => {
let mut rng = thread_rng();

let mut json_values = if json { Some(vec![]) } else { None };
let mut json_values = if shell::is_json() { Some(vec![]) } else { None };
if let Some(path) = path {
let path = match dunce::canonicalize(path.clone()) {
Ok(path) => path,
Expand Down Expand Up @@ -294,7 +286,7 @@ impl WalletSubcommands {
}
}
}
Self::NewMnemonic { words, accounts, entropy, json } => {
Self::NewMnemonic { words, accounts, entropy } => {
let phrase = if let Some(entropy) = entropy {
let entropy = Entropy::from_slice(hex::decode(entropy)?)?;
Mnemonic::<English>::new_from_entropy(entropy).to_phrase()
Expand All @@ -303,7 +295,9 @@ impl WalletSubcommands {
Mnemonic::<English>::new_with_count(&mut rng, words)?.to_phrase()
};

if !json {
let format_json = shell::is_json();

if !format_json {
sh_println!("{}", "Generating mnemonic from provided entropy...".yellow())?;
}

Expand All @@ -315,7 +309,7 @@ impl WalletSubcommands {
let wallets =
wallets.into_iter().map(|b| b.build()).collect::<Result<Vec<_>, _>>()?;

if !json {
if !format_json {
sh_println!("{}", "Successfully generated a new mnemonic.".green())?;
sh_println!("Phrase:\n{phrase}")?;
sh_println!("\nAccounts:")?;
Expand All @@ -324,7 +318,7 @@ impl WalletSubcommands {
let mut accounts = json!([]);
for (i, wallet) in wallets.iter().enumerate() {
let private_key = hex::encode(wallet.credential().to_bytes());
if json {
if format_json {
accounts.as_array_mut().unwrap().push(json!({
"address": format!("{}", wallet.address()),
"private_key": format!("0x{}", private_key),
Expand All @@ -336,7 +330,7 @@ impl WalletSubcommands {
}
}

if json {
if format_json {
let obj = json!({
"mnemonic": phrase,
"accounts": accounts,
Expand Down
Loading

0 comments on commit e2a6282

Please sign in to comment.