From f564f2e6860a6277ff39ac77ecdea45e671e7f46 Mon Sep 17 00:00:00 2001 From: Ryan Hunt Date: Thu, 4 Jan 2018 17:06:46 -0600 Subject: [PATCH] Add an Error type --- src/bindgen/builder.rs | 3 +- src/bindgen/cargo/cargo.rs | 17 +++++----- src/bindgen/cargo/cargo_expand.rs | 38 +++++++++++++++++----- src/bindgen/cargo/mod.rs | 8 ++--- src/bindgen/error.rs | 40 +++++++++++++++++++++++ src/bindgen/library.rs | 3 +- src/bindgen/mod.rs | 2 ++ src/bindgen/parser.rs | 53 ++++++++++++++++++------------- src/lib.rs | 4 +-- src/main.rs | 4 +-- 10 files changed, 123 insertions(+), 49 deletions(-) create mode 100644 src/bindgen/error.rs diff --git a/src/bindgen/builder.rs b/src/bindgen/builder.rs index 97bb942..0b4dd54 100644 --- a/src/bindgen/builder.rs +++ b/src/bindgen/builder.rs @@ -6,6 +6,7 @@ use std::path; use bindgen::cargo::Cargo; use bindgen::config::{Braces, Config, Language}; +use bindgen::error::Error; use bindgen::library::Library; use bindgen::bindings::Bindings; use bindgen::parser::{self, Parse}; @@ -200,7 +201,7 @@ impl Builder { self } - pub fn generate(self) -> Result { + pub fn generate(self) -> Result { let mut result = Parse::new(); if self.std_types { diff --git a/src/bindgen/cargo/cargo.rs b/src/bindgen/cargo/cargo.rs index 3379811..c0bc7d3 100644 --- a/src/bindgen/cargo/cargo.rs +++ b/src/bindgen/cargo/cargo.rs @@ -8,6 +8,7 @@ use bindgen::cargo::cargo_expand; use bindgen::cargo::cargo_lock::{self, Lock}; use bindgen::cargo::cargo_metadata::{self, Metadata}; use bindgen::cargo::cargo_toml; +use bindgen::error::Error; /// Parse a dependency string used in Cargo.lock fn parse_dep_string(dep_string: &str) -> (&str, &str) { @@ -40,7 +41,7 @@ impl Cargo { crate_dir: &Path, binding_crate_name: Option<&str>, use_cargo_lock: bool, - ) -> Result { + ) -> Result { let toml_path = crate_dir.join("Cargo.toml"); let lock_path = crate_dir.join("Cargo.lock"); @@ -48,7 +49,7 @@ impl Cargo { match cargo_lock::lock(&lock_path) { Ok(lock) => Some(lock), Err(x) => { - warn!("couldn't load lock file {:?}: {:?}", lock_path, x); + warn!("Couldn't load lock file {:?}: {:?}", lock_path, x); None } } @@ -56,15 +57,13 @@ impl Cargo { None }; let metadata = cargo_metadata::metadata(&toml_path).map_err(|x| { - format!( - "couldn't execute `cargo metadata` with manifest {:?}: {:?}", - toml_path, x - ) + Error::CargoMetadata(toml_path.to_str().unwrap().to_owned(), x) })?; // Use the specified binding crate name or infer it from the manifest - let manifest = cargo_toml::manifest(&toml_path) - .map_err(|_| format!("couldn't load {:?}.", toml_path))?; + let manifest = cargo_toml::manifest(&toml_path).map_err(|x| { + Error::CargoToml(toml_path.to_str().unwrap().to_owned(), x) + })?; let binding_crate_name = binding_crate_name.map_or(manifest.package.name.clone(), |x| x.to_owned()); @@ -191,7 +190,7 @@ impl Cargo { None } - pub(crate) fn expand_crate(&self, package: &PackageRef) -> Result { + pub(crate) fn expand_crate(&self, package: &PackageRef) -> Result { cargo_expand::expand(&self.manifest_path, &package.name, &package.version) } } diff --git a/src/bindgen/cargo/cargo_expand.rs b/src/bindgen/cargo/cargo_expand.rs index ea5b379..5752b0f 100644 --- a/src/bindgen/cargo/cargo_expand.rs +++ b/src/bindgen/cargo/cargo_expand.rs @@ -3,16 +3,39 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ use std::env; +use std::io; use std::path::Path; use std::process::Command; -use std::str::from_utf8; +use std::str::{Utf8Error, from_utf8}; extern crate tempdir; use self::tempdir::TempDir; +#[derive(Debug)] +/// Possible errors that can occur during `rustc --pretty=expanded`. +pub enum Error { + /// Error during creation of temporary directory + Io(io::Error), + /// Output of `cargo metadata` was not valid utf8 + Utf8(Utf8Error), + /// Error during execution of `cargo rustc --pretty=expanded` + Compile(String), +} + +impl From for Error { + fn from(err: io::Error) -> Self { + Error::Io(err) + } +} +impl From for Error { + fn from(err: Utf8Error) -> Self { + Error::Utf8(err) + } +} + /// Use rustc to expand and pretty print the crate into a single file, /// removing any macros in the process. -pub fn expand(manifest_path: &Path, crate_name: &str, version: &str) -> Result { +pub fn expand(manifest_path: &Path, crate_name: &str, version: &str) -> Result { let cargo = env::var("CARGO").unwrap_or_else(|_| String::from("cargo")); let run = |target_dir: &Path| { let mut cmd = Command::new(cargo); @@ -27,13 +50,13 @@ pub fn expand(manifest_path: &Path, crate_name: &str, version: &str) -> Result Result fmt::Result { + match self { + &Error::CargoMetadata(ref path, ref error) => { + write!(f, "Couldn't execute `cargo metadata` with manifest {:?}: {:?}", path, error) + } + &Error::CargoToml(ref path, ref error) => { + write!(f, "Couldn't load manifest file {:?}: {:?}", path, error) + } + &Error::CargoExpand(ref crate_name, ref error) => { + write!(f, "Parsing crate `{}`: couldn't run `cargo rustc --pretty=expanded`: {:?}", crate_name, error) + } + &Error::ParseSyntaxError{ref crate_name, ref src_path, ref message} => { + write!(f, "Parsing crate `{}`:`{}`:\n{}", crate_name, src_path, message) + } + &Error::ParseCannotOpenFile{ref crate_name, ref src_path} => { + write!(f, "Parsing crate `{}`: cannot open file `{}`.", crate_name, src_path) + } + } + } +} diff --git a/src/bindgen/library.rs b/src/bindgen/library.rs index 588f157..1d61ef4 100644 --- a/src/bindgen/library.rs +++ b/src/bindgen/library.rs @@ -8,6 +8,7 @@ use std::mem; use bindgen::bindings::Bindings; use bindgen::config::{Config, Language}; use bindgen::dependencies::Dependencies; +use bindgen::error::Error; use bindgen::ir::{Constant, Enum, Function, Item, ItemContainer, ItemMap}; use bindgen::ir::{OpaqueItem, Path, Static, Struct, Typedef, Union}; use bindgen::monomorph::Monomorphs; @@ -50,7 +51,7 @@ impl Library { } } - pub fn generate(mut self) -> Result { + pub fn generate(mut self) -> Result { self.functions.sort_by(|x, y| x.name.cmp(&y.name)); self.transfer_annotations(); diff --git a/src/bindgen/mod.rs b/src/bindgen/mod.rs index 9434203..11c6c33 100644 --- a/src/bindgen/mod.rs +++ b/src/bindgen/mod.rs @@ -40,6 +40,7 @@ mod cargo; mod cdecl; mod config; mod dependencies; +mod error; mod ir; mod library; mod mangle; @@ -55,3 +56,4 @@ pub(crate) use self::cargo::*; pub use self::config::*; pub use self::bindings::Bindings; pub use self::builder::Builder; +pub use self::error::Error; diff --git a/src/bindgen/parser.rs b/src/bindgen/parser.rs index edd16b3..40957a4 100644 --- a/src/bindgen/parser.rs +++ b/src/bindgen/parser.rs @@ -10,6 +10,7 @@ use std::path::{Path, PathBuf}; use syn; use bindgen::cargo::{Cargo, PackageRef}; +use bindgen::error::Error; use bindgen::ir::{AnnotationSet, Cfg, Constant, Documentation, Enum, Function, GenericParams}; use bindgen::ir::{ItemMap, OpaqueItem, Static, Struct, Typedef, Union}; use bindgen::utilities::{SynAbiHelpers, SynItemHelpers}; @@ -23,7 +24,7 @@ const STD_CRATES: &'static [&'static str] = &[ "proc_macro", ]; -type ParseResult = Result; +type ParseResult = Result; /// Parses a single rust source file, not following `mod` or `extern crate`. pub fn parse_src(src_file: &Path) -> ParseResult { @@ -128,7 +129,7 @@ impl Parser { return !STD_CRATES.contains(&pkg_name.as_ref()) && !self.exclude.contains(&pkg_name); } - fn parse_crate(&mut self, pkg: &PackageRef) -> Result<(), String> { + fn parse_crate(&mut self, pkg: &PackageRef) -> Result<(), Error> { assert!(self.lib.is_some()); self.parsed_crates.insert(pkg.name.clone()); @@ -153,14 +154,22 @@ impl Parser { } } - fn parse_expand_crate(&mut self, pkg: &PackageRef) -> Result<(), String> { + fn parse_expand_crate(&mut self, pkg: &PackageRef) -> Result<(), Error> { assert!(self.lib.is_some()); let mod_parsed = { if !self.cache_expanded_crate.contains_key(&pkg.name) { - let s = self.lib.as_ref().unwrap().expand_crate(pkg)?; + let s = self.lib.as_ref().unwrap().expand_crate(pkg) + .map_err(|x| Error::CargoExpand( + pkg.name.clone(), + x + ))?; let i = syn::parse_crate(&s) - .map_err(|msg| format!("Parsing crate `{}`:\n{}.", pkg.name, msg))?; + .map_err(|msg| Error::ParseSyntaxError{ + crate_name: pkg.name.clone(), + src_path: "".to_owned(), + message: msg, + })?; self.cache_expanded_crate.insert(pkg.name.clone(), i.items); } @@ -174,7 +183,7 @@ impl Parser { &mut self, pkg: &PackageRef, items: &Vec, - ) -> Result<(), String> { + ) -> Result<(), Error> { self.out.load_syn_crate_mod( &self.binding_crate_name, &pkg.name, @@ -193,11 +202,7 @@ impl Parser { if let &Some(ref inline_items) = inline_items { self.process_expanded_mod(pkg, inline_items)?; } else { - error!( - "Parsing crate `{}`: external mod found in expanded source, \ - this shouldn't be possible.", - pkg.name - ); + unreachable!(); } if cfg.is_some() { @@ -246,7 +251,7 @@ impl Parser { Ok(()) } - fn parse_mod(&mut self, pkg: &PackageRef, mod_path: &Path) -> Result<(), String> { + fn parse_mod(&mut self, pkg: &PackageRef, mod_path: &Path) -> Result<(), Error> { let mod_parsed = { let owned_mod_path = mod_path.to_path_buf(); @@ -261,20 +266,24 @@ impl Parser { let mut s = String::new(); let mut f = File::open(mod_path).map_err(|_| { - format!( - "Parsing crate `{}`: cannot open file `{:?}`.", - pkg.name, mod_path - ) + Error::ParseCannotOpenFile{ + crate_name: pkg.name.clone(), + src_path: mod_path.to_str().unwrap().to_owned(), + } })?; f.read_to_string(&mut s).map_err(|_| { - format!( - "Parsing crate `{}`: cannot open file `{:?}`.", - pkg.name, mod_path - ) + Error::ParseCannotOpenFile{ + crate_name: pkg.name.clone(), + src_path: mod_path.to_str().unwrap().to_owned(), + } })?; let i = syn::parse_crate(&s).map_err(|msg| { - format!("Parsing crate `{}`:\n{}.", pkg.name, limit_string(&msg)) + Error::ParseSyntaxError{ + crate_name: pkg.name.clone(), + src_path: "".to_owned(), + message: limit_string(&msg).to_owned(), + } })?; self.cache_src.insert(owned_mod_path.clone(), i.items); @@ -293,7 +302,7 @@ impl Parser { pkg: &PackageRef, mod_dir: &Path, items: &Vec, - ) -> Result<(), String> { + ) -> Result<(), Error> { self.out.load_syn_crate_mod( &self.binding_crate_name, &pkg.name, diff --git a/src/lib.rs b/src/lib.rs index 41d7d12..0530e6a 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -18,7 +18,7 @@ use std::path::Path; /// A utility function for build scripts to generate bindings for a crate, using /// a `cbindgen.toml` if it exists. -pub fn generate>(crate_dir: P) -> Result { +pub fn generate>(crate_dir: P) -> Result { let config = Config::from_root_or_default(crate_dir.as_ref()); generate_with_config(crate_dir, config) @@ -29,7 +29,7 @@ pub fn generate>(crate_dir: P) -> Result { pub fn generate_with_config>( crate_dir: P, config: Config, -) -> Result { +) -> Result { Builder::new() .with_config(config) .with_crate(crate_dir) diff --git a/src/main.rs b/src/main.rs index 4e92548..e6dbb08 100644 --- a/src/main.rs +++ b/src/main.rs @@ -20,7 +20,7 @@ use clap::{App, Arg, ArgMatches}; mod logging; mod bindgen; -use bindgen::{Bindings, Builder, Cargo, Config, Language}; +use bindgen::{Bindings, Builder, Cargo, Config, Error, Language}; fn apply_config_overrides<'a>(config: &mut Config, matches: &ArgMatches<'a>) { // We allow specifying a language to override the config default. This is @@ -43,7 +43,7 @@ fn apply_config_overrides<'a>(config: &mut Config, matches: &ArgMatches<'a>) { } } -fn load_bindings<'a>(input: &Path, matches: &ArgMatches<'a>) -> Result { +fn load_bindings<'a>(input: &Path, matches: &ArgMatches<'a>) -> Result { // If a file is specified then we load it as a single source if !input.is_dir() { // Load any config specified or search in the input directory