summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorBastian Köcher <git@kchr.de>2017-08-11 17:59:32 +0200
committerBastian Köcher <git@kchr.de>2017-08-14 18:34:53 +0200
commit170f4f57ccd893becbefad947e7862d0917c83c4 (patch)
treebd774189a922babd2dc0da084fa0c2adac9f5ccc /src
parentf9087f3bb48eccf23f9388885a99b19ee18d41e7 (diff)
Adds support for running rustfmt on generated bindings
This patch enables bindgen to run rustfmt on generated bindings. Rustfmt is used from the global PATH. Two new command-line arguments are added: 1. --format-bindings: Enables running rustfmt 2. --format-configuration-file: The configuration file for rustfmt (not required).
Diffstat (limited to 'src')
-rw-r--r--src/lib.rs79
-rw-r--r--src/options.rs37
2 files changed, 107 insertions, 9 deletions
diff --git a/src/lib.rs b/src/lib.rs
index e72800c0..431fea0e 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -26,6 +26,7 @@ extern crate peeking_take_while;
extern crate regex;
#[macro_use]
extern crate lazy_static;
+extern crate which;
#[cfg(feature = "logging")]
#[macro_use]
@@ -455,6 +456,16 @@ impl Builder {
);
}
+ if !self.options.format_bindings {
+ output_vector.push("--format-bindings".into());
+ }
+
+ if let Some(path) = self.options.format_configuration_file.as_ref().and_then(
+ |f| f.to_str()) {
+ output_vector.push("--format-configuration-file".into());
+ output_vector.push(path.into());
+ }
+
output_vector
}
@@ -840,6 +851,19 @@ impl Builder {
self
}
+ /// Set whether rustfmt should format the generated bindings.
+ pub fn format_bindings(mut self, doit: bool) -> Self {
+ self.options.format_bindings = doit;
+ self
+ }
+
+ /// Set the absolute path to the rustfmt configuration file, if None, the standard rustfmt
+ /// options are used.
+ pub fn format_configuration_file(mut self, path: Option<PathBuf>) -> Self {
+ self.options.format_configuration_file = path;
+ self
+ }
+
/// Generate the Rust bindings using the options built up thus far.
pub fn generate<'ctx>(mut self) -> Result<Bindings<'ctx>, ()> {
self.options.input_header = self.input_headers.pop();
@@ -1099,6 +1123,13 @@ pub struct BindgenOptions {
/// Features to enable, derived from `rust_target`
rust_features: RustFeatures,
+
+ /// Whether rustfmt should format the generated bindings.
+ pub format_bindings: bool,
+
+ /// The absolute path to the rustfmt configuration file, if None, the standard rustfmt
+ /// options are used.
+ pub format_configuration_file: Option<PathBuf>,
}
/// TODO(emilio): This is sort of a lie (see the error message that results from
@@ -1183,6 +1214,8 @@ impl Default for BindgenOptions {
objc_extern_crate: false,
enable_mangling: true,
prepend_enum_name: true,
+ format_bindings: true,
+ format_configuration_file: None,
}
}
}
@@ -1334,14 +1367,19 @@ impl<'ctx> Bindings<'ctx> {
/// Write these bindings as source text to a file.
pub fn write_to_file<P: AsRef<Path>>(&self, path: P) -> io::Result<()> {
- let file = try!(
- OpenOptions::new()
- .write(true)
- .truncate(true)
- .create(true)
- .open(path)
- );
- self.write(Box::new(file))
+ {
+ let file = try!(
+ OpenOptions::new()
+ .write(true)
+ .truncate(true)
+ .create(true)
+ .open(path.as_ref())
+ );
+ self.write(Box::new(file))?;
+ }
+
+ self.format_generated_file(path.as_ref());
+ Ok(())
}
/// Write these bindings as source text to the given `Write`able.
@@ -1364,6 +1402,31 @@ impl<'ctx> Bindings<'ctx> {
try!(eof(&mut ps.s));
ps.s.out.flush()
}
+
+ /// Checks if format_bindings is set and runs rustfmt on the file
+ fn format_generated_file(&self, file: &Path) {
+ if !self.context.options().format_bindings {
+ return;
+ }
+
+ let rustfmt = if let Ok(rustfmt) = which::which("rustfmt") {
+ rustfmt
+ } else {
+ error!("Could not find rustfmt in the global path.");
+ return;
+ };
+
+ let mut cmd = Command::new(rustfmt);
+
+ if let Some(path) = self.context.options().format_configuration_file.as_ref().and_then(
+ |f| f.to_str()) {
+ cmd.args(&["--config-path", path]);
+ }
+
+ if let Err(e) = cmd.arg(file).status() {
+ error!("Error executing rustfmt (exit code: {:?}).", e);
+ }
+ }
}
/// Determines whether the given cursor is in any of the files matched by the
diff --git a/src/options.rs b/src/options.rs
index 28faea99..074807c8 100644
--- a/src/options.rs
+++ b/src/options.rs
@@ -4,6 +4,7 @@ use clap::{App, Arg};
use std::fs::File;
use std::io::{self, Error, ErrorKind, Write, stderr};
use std::str::FromStr;
+use std::path::PathBuf;
/// Construct a new [`Builder`](./struct.Builder.html) from command line flags.
pub fn builder_from_flags<I>(
@@ -231,7 +232,20 @@ where
.help("Preprocess and dump the input header files to disk. \
Useful when debugging bindgen, using C-Reduce, or when \
filing issues. The resulting file will be named \
- something like `__bindgen.i` or `__bindgen.ii`.")
+ something like `__bindgen.i` or `__bindgen.ii`."),
+ Arg::with_name("format-bindings")
+ .long("format-bindings")
+ .help("Format the generated bindings with rustfmt. \
+ Rustfmt needs to be in the global PATH."),
+ Arg::with_name("format-configuration-file")
+ .long("format-configuration-file")
+ .help("The absolute path to the rustfmt configuration file. \
+ The configuration file will be used for formatting the bindings \
+ (when enabled by --format-bindings).")
+ .value_name("path")
+ .takes_value(true)
+ .multiple(false)
+ .number_of_values(1),
]) // .args()
.get_matches_from(args);
@@ -458,6 +472,27 @@ where
builder.dump_preprocessed_input()?;
}
+ if matches.is_present("format-bindings") {
+ builder = builder.format_bindings(true);
+ }
+
+ if let Some(path_str) = matches.value_of("format-configuration-file") {
+ let path = PathBuf::from(path_str);
+
+ if !path.is_absolute() {
+ return Err(Error::new(ErrorKind::Other,
+ "--format-configuration--file needs to be an absolute path!"));
+ }
+
+ if path.to_str().is_none() {
+ return Err(
+ Error::new(ErrorKind::Other,
+ "--format-configuration-file contains non-valid UTF8 characters."));
+ }
+
+ builder = builder.format_configuration_file(Some(path));
+ }
+
let verbose = matches.is_present("verbose");
Ok((builder, output, verbose))