feat(abigen): use prettyplease (#2027)
This commit is contained in:
parent
c439566625
commit
0187bedd11
|
@ -1378,6 +1378,7 @@ dependencies = [
|
||||||
"eyre",
|
"eyre",
|
||||||
"getrandom 0.2.8",
|
"getrandom 0.2.8",
|
||||||
"hex",
|
"hex",
|
||||||
|
"prettyplease",
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"regex",
|
"regex",
|
||||||
|
@ -3162,6 +3163,16 @@ dependencies = [
|
||||||
"yansi",
|
"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]]
|
[[package]]
|
||||||
name = "primitive-types"
|
name = "primitive-types"
|
||||||
version = "0.12.1"
|
version = "0.12.1"
|
||||||
|
|
|
@ -16,10 +16,12 @@ keywords = ["ethereum", "web3", "celo", "ethers"]
|
||||||
[dependencies]
|
[dependencies]
|
||||||
ethers-core = { version = "^1.0.0", path = "../../ethers-core", features = ["macros"] }
|
ethers-core = { version = "^1.0.0", path = "../../ethers-core", features = ["macros"] }
|
||||||
|
|
||||||
Inflector = "0.11"
|
|
||||||
proc-macro2 = "1.0"
|
proc-macro2 = "1.0"
|
||||||
quote = "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"
|
url = "2.1"
|
||||||
serde_json = "1.0.61"
|
serde_json = "1.0.61"
|
||||||
serde = { version = "1.0.124", features = ["derive"] }
|
serde = { version = "1.0.124", features = ["derive"] }
|
||||||
|
|
|
@ -16,7 +16,6 @@ pub mod contract;
|
||||||
pub use contract::structs::InternalStructs;
|
pub use contract::structs::InternalStructs;
|
||||||
use contract::Context;
|
use contract::Context;
|
||||||
|
|
||||||
mod rustfmt;
|
|
||||||
mod source;
|
mod source;
|
||||||
mod util;
|
mod util;
|
||||||
|
|
||||||
|
@ -69,8 +68,8 @@ pub struct Abigen {
|
||||||
/// Derives added to event structs and enums.
|
/// Derives added to event structs and enums.
|
||||||
event_derives: Vec<String>,
|
event_derives: Vec<String>,
|
||||||
|
|
||||||
/// Format the code using a locally installed copy of `rustfmt`.
|
/// Whether to format the code. Uses [`prettyplease`].
|
||||||
rustfmt: bool,
|
format: bool,
|
||||||
|
|
||||||
/// Manually specified event name aliases.
|
/// Manually specified event name aliases.
|
||||||
event_aliases: HashMap<String, String>,
|
event_aliases: HashMap<String, String>,
|
||||||
|
@ -89,7 +88,7 @@ impl Abigen {
|
||||||
method_aliases: HashMap::new(),
|
method_aliases: HashMap::new(),
|
||||||
event_derives: Vec::new(),
|
event_derives: Vec::new(),
|
||||||
event_aliases: HashMap::new(),
|
event_aliases: HashMap::new(),
|
||||||
rustfmt: true,
|
format: true,
|
||||||
error_aliases: Default::default(),
|
error_aliases: Default::default(),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
@ -147,14 +146,20 @@ impl Abigen {
|
||||||
self
|
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]
|
#[must_use]
|
||||||
|
#[deprecated = "Use format instead"]
|
||||||
|
#[doc(hidden)]
|
||||||
pub fn rustfmt(mut self, rustfmt: bool) -> Self {
|
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
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -173,10 +178,10 @@ impl Abigen {
|
||||||
|
|
||||||
/// Generates the contract bindings.
|
/// Generates the contract bindings.
|
||||||
pub fn generate(self) -> Result<ContractBindings> {
|
pub fn generate(self) -> Result<ContractBindings> {
|
||||||
let rustfmt = self.rustfmt;
|
let format = self.format;
|
||||||
let name = self.contract_name.clone();
|
let name = self.contract_name.clone();
|
||||||
let (expanded, _) = self.expand()?;
|
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
|
/// 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.
|
/// The TokenStream representing the contract bindings.
|
||||||
tokens: TokenStream,
|
tokens: TokenStream,
|
||||||
/// The output options used for serialization.
|
/// The output options used for serialization.
|
||||||
rustfmt: bool,
|
format: bool,
|
||||||
/// The contract name
|
/// The contract name
|
||||||
name: String,
|
name: String,
|
||||||
}
|
}
|
||||||
|
@ -204,14 +209,11 @@ impl ContractBindings {
|
||||||
where
|
where
|
||||||
W: Write,
|
W: Write,
|
||||||
{
|
{
|
||||||
let source = {
|
let source = if self.format {
|
||||||
let raw = self.tokens.to_string();
|
let syntax_tree = syn::parse2::<syn::File>(self.tokens.clone()).unwrap();
|
||||||
|
prettyplease::unparse(&syntax_tree)
|
||||||
if self.rustfmt {
|
|
||||||
rustfmt::format(&raw).unwrap_or(raw)
|
|
||||||
} else {
|
} else {
|
||||||
raw
|
self.tokens.to_string()
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
w.write_all(source.as_bytes())?;
|
w.write_all(source.as_bytes())?;
|
||||||
|
|
|
@ -139,11 +139,8 @@ impl MultiAbigen {
|
||||||
|
|
||||||
/// Build the contract bindings and prepare for writing
|
/// Build the contract bindings and prepare for writing
|
||||||
pub fn build(self) -> Result<MultiBindings> {
|
pub fn build(self) -> Result<MultiBindings> {
|
||||||
let rustfmt = self.abigens.iter().any(|gen| gen.rustfmt);
|
let format = self.abigens.iter().any(|gen| gen.format);
|
||||||
Ok(MultiBindings {
|
Ok(MultiBindings { expansion: MultiExpansion::from_abigen(self.abigens)?.expand(), format })
|
||||||
expansion: MultiExpansion::from_abigen(self.abigens)?.expand(),
|
|
||||||
rustfmt,
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -298,14 +295,14 @@ impl MultiExpansionResult {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Converts this result into [`MultiBindingsInner`]
|
/// 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);
|
self.set_shared_import_path(single_file);
|
||||||
let Self { contracts, shared_types, root, .. } = self;
|
let Self { contracts, shared_types, root, .. } = self;
|
||||||
let bindings = contracts
|
let bindings = contracts
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.map(|(expanded, ctx)| ContractBindings {
|
.map(|(expanded, ctx)| ContractBindings {
|
||||||
tokens: expanded.into_tokens(),
|
tokens: expanded.into_tokens(),
|
||||||
rustfmt,
|
format,
|
||||||
name: ctx.contract_name().to_string(),
|
name: ctx.contract_name().to_string(),
|
||||||
})
|
})
|
||||||
.map(|v| (v.name.clone(), v))
|
.map(|v| (v.name.clone(), v))
|
||||||
|
@ -325,7 +322,7 @@ impl MultiExpansionResult {
|
||||||
};
|
};
|
||||||
Some(ContractBindings {
|
Some(ContractBindings {
|
||||||
tokens: shared_types,
|
tokens: shared_types,
|
||||||
rustfmt,
|
format,
|
||||||
name: "shared_types".to_string(),
|
name: "shared_types".to_string(),
|
||||||
})
|
})
|
||||||
} else {
|
} else {
|
||||||
|
@ -364,7 +361,7 @@ impl MultiExpansionResult {
|
||||||
/// changed)
|
/// changed)
|
||||||
pub struct MultiBindings {
|
pub struct MultiBindings {
|
||||||
expansion: MultiExpansionResult,
|
expansion: MultiExpansionResult,
|
||||||
rustfmt: bool,
|
format: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl MultiBindings {
|
impl MultiBindings {
|
||||||
|
@ -378,18 +375,25 @@ impl MultiBindings {
|
||||||
self.expansion.contracts.is_empty()
|
self.expansion.contracts.is_empty()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Specify whether or not to format the code using a locally installed copy
|
#[must_use]
|
||||||
/// of `rustfmt`.
|
#[deprecated = "Use format instead"]
|
||||||
///
|
#[doc(hidden)]
|
||||||
/// Note that in case `rustfmt` does not exist or produces an error, the
|
|
||||||
/// unformatted code will be used.
|
|
||||||
pub fn rustfmt(mut self, rustfmt: bool) -> Self {
|
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
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
fn into_inner(self, single_file: bool) -> MultiBindingsInner {
|
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
|
/// Generates all the bindings and writes them to the given module
|
||||||
|
|
|
@ -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)
|
|
||||||
}
|
|
Loading…
Reference in New Issue