feat(abigen): use prettyplease (#2027)

This commit is contained in:
DaniPopes 2023-01-09 06:17:22 +01:00 committed by GitHub
parent c439566625
commit 0187bedd11
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 58 additions and 75 deletions

11
Cargo.lock generated
View File

@ -1378,6 +1378,7 @@ dependencies = [
"eyre",
"getrandom 0.2.8",
"hex",
"prettyplease",
"proc-macro2",
"quote",
"regex",
@ -3162,6 +3163,16 @@ dependencies = [
"yansi",
]
[[package]]
name = "prettyplease"
version = "0.1.23"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e97e3215779627f01ee256d2fad52f3d95e8e1c11e9fc6fd08f7cd455d5d5c78"
dependencies = [
"proc-macro2",
"syn",
]
[[package]]
name = "primitive-types"
version = "0.12.1"

View File

@ -16,10 +16,12 @@ keywords = ["ethereum", "web3", "celo", "ethers"]
[dependencies]
ethers-core = { version = "^1.0.0", path = "../../ethers-core", features = ["macros"] }
Inflector = "0.11"
proc-macro2 = "1.0"
quote = "1.0"
syn = "1.0.12"
syn = { version = "1.0.12", default-features = false, features = ["full"] }
prettyplease = "0.1.23"
Inflector = "0.11"
url = "2.1"
serde_json = "1.0.61"
serde = { version = "1.0.124", features = ["derive"] }

View File

@ -16,7 +16,6 @@ pub mod contract;
pub use contract::structs::InternalStructs;
use contract::Context;
mod rustfmt;
mod source;
mod util;
@ -69,8 +68,8 @@ pub struct Abigen {
/// Derives added to event structs and enums.
event_derives: Vec<String>,
/// Format the code using a locally installed copy of `rustfmt`.
rustfmt: bool,
/// Whether to format the code. Uses [`prettyplease`].
format: bool,
/// Manually specified event name aliases.
event_aliases: HashMap<String, String>,
@ -89,7 +88,7 @@ impl Abigen {
method_aliases: HashMap::new(),
event_derives: Vec::new(),
event_aliases: HashMap::new(),
rustfmt: true,
format: true,
error_aliases: Default::default(),
})
}
@ -147,14 +146,20 @@ impl Abigen {
self
}
/// Specify whether or not to format the code using a locally installed copy
/// of `rustfmt`.
///
/// Note that in case `rustfmt` does not exist or produces an error, the
/// unformatted code will be used.
#[must_use]
#[deprecated = "Use format instead"]
#[doc(hidden)]
pub fn rustfmt(mut self, rustfmt: bool) -> Self {
self.rustfmt = rustfmt;
self.format = rustfmt;
self
}
/// Specify whether to format the code or not. True by default.
///
/// This will use [`prettyplease`], so the resulting formatted code **will not** be affected by
/// the local `rustfmt` version or config.
pub fn format(mut self, format: bool) -> Self {
self.format = format;
self
}
@ -173,10 +178,10 @@ impl Abigen {
/// Generates the contract bindings.
pub fn generate(self) -> Result<ContractBindings> {
let rustfmt = self.rustfmt;
let format = self.format;
let name = self.contract_name.clone();
let (expanded, _) = self.expand()?;
Ok(ContractBindings { tokens: expanded.into_tokens(), rustfmt, name })
Ok(ContractBindings { tokens: expanded.into_tokens(), format, name })
}
/// Expands the `Abigen` and returns the [`ExpandedContract`] that holds all tokens and the
@ -193,7 +198,7 @@ pub struct ContractBindings {
/// The TokenStream representing the contract bindings.
tokens: TokenStream,
/// The output options used for serialization.
rustfmt: bool,
format: bool,
/// The contract name
name: String,
}
@ -204,14 +209,11 @@ impl ContractBindings {
where
W: Write,
{
let source = {
let raw = self.tokens.to_string();
if self.rustfmt {
rustfmt::format(&raw).unwrap_or(raw)
} else {
raw
}
let source = if self.format {
let syntax_tree = syn::parse2::<syn::File>(self.tokens.clone()).unwrap();
prettyplease::unparse(&syntax_tree)
} else {
self.tokens.to_string()
};
w.write_all(source.as_bytes())?;

View File

@ -139,11 +139,8 @@ impl MultiAbigen {
/// Build the contract bindings and prepare for writing
pub fn build(self) -> Result<MultiBindings> {
let rustfmt = self.abigens.iter().any(|gen| gen.rustfmt);
Ok(MultiBindings {
expansion: MultiExpansion::from_abigen(self.abigens)?.expand(),
rustfmt,
})
let format = self.abigens.iter().any(|gen| gen.format);
Ok(MultiBindings { expansion: MultiExpansion::from_abigen(self.abigens)?.expand(), format })
}
}
@ -298,14 +295,14 @@ impl MultiExpansionResult {
}
/// Converts this result into [`MultiBindingsInner`]
fn into_bindings(mut self, single_file: bool, rustfmt: bool) -> MultiBindingsInner {
fn into_bindings(mut self, single_file: bool, format: bool) -> MultiBindingsInner {
self.set_shared_import_path(single_file);
let Self { contracts, shared_types, root, .. } = self;
let bindings = contracts
.into_iter()
.map(|(expanded, ctx)| ContractBindings {
tokens: expanded.into_tokens(),
rustfmt,
format,
name: ctx.contract_name().to_string(),
})
.map(|v| (v.name.clone(), v))
@ -325,7 +322,7 @@ impl MultiExpansionResult {
};
Some(ContractBindings {
tokens: shared_types,
rustfmt,
format,
name: "shared_types".to_string(),
})
} else {
@ -364,7 +361,7 @@ impl MultiExpansionResult {
/// changed)
pub struct MultiBindings {
expansion: MultiExpansionResult,
rustfmt: bool,
format: bool,
}
impl MultiBindings {
@ -378,18 +375,25 @@ impl MultiBindings {
self.expansion.contracts.is_empty()
}
/// Specify whether or not to format the code using a locally installed copy
/// of `rustfmt`.
///
/// Note that in case `rustfmt` does not exist or produces an error, the
/// unformatted code will be used.
#[must_use]
#[deprecated = "Use format instead"]
#[doc(hidden)]
pub fn rustfmt(mut self, rustfmt: bool) -> Self {
self.rustfmt = rustfmt;
self.format = rustfmt;
self
}
/// Specify whether to format the code or not. True by default.
///
/// This will use [`prettyplease`], so the resulting formatted code **will not** be affected by
/// the local `rustfmt` version or config.
pub fn format(mut self, format: bool) -> Self {
self.format = format;
self
}
fn into_inner(self, single_file: bool) -> MultiBindingsInner {
self.expansion.into_bindings(single_file, self.rustfmt)
self.expansion.into_bindings(single_file, self.format)
}
/// Generates all the bindings and writes them to the given module

View File

@ -1,36 +0,0 @@
//! This module implements basic `rustfmt` code formatting.
use eyre::{eyre, Result};
use std::{
io::Write,
process::{Command, Stdio},
};
/// Format the raw input source string and return formatted output.
pub fn format<S>(source: S) -> Result<String>
where
S: AsRef<str>,
{
let mut rustfmt =
Command::new("rustfmt").stdin(Stdio::piped()).stdout(Stdio::piped()).spawn()?;
{
let stdin = rustfmt
.stdin
.as_mut()
.ok_or_else(|| eyre!("stdin was not created for `rustfmt` child process"))?;
stdin.write_all(source.as_ref().as_bytes())?;
}
let output = rustfmt.wait_with_output()?;
eyre::ensure!(
output.status.success(),
"`rustfmt` exited with code {}:\n{}",
output.status,
String::from_utf8_lossy(&output.stderr),
);
let stdout = String::from_utf8(output.stdout)?;
Ok(stdout)
}