Add an Error type

This commit is contained in:
Ryan Hunt
2018-01-04 17:06:46 -06:00
parent 21d917b723
commit f564f2e686
10 changed files with 123 additions and 49 deletions
+2 -1
View File
@@ -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<Bindings, String> {
pub fn generate(self) -> Result<Bindings, Error> {
let mut result = Parse::new();
if self.std_types {
+8 -9
View File
@@ -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<Cargo, String> {
) -> Result<Cargo, Error> {
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<String, String> {
pub(crate) fn expand_crate(&self, package: &PackageRef) -> Result<String, cargo_expand::Error> {
cargo_expand::expand(&self.manifest_path, &package.name, &package.version)
}
}
+30 -8
View File
@@ -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<io::Error> for Error {
fn from(err: io::Error) -> Self {
Error::Io(err)
}
}
impl From<Utf8Error> 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<String, String> {
pub fn expand(manifest_path: &Path, crate_name: &str, version: &str) -> Result<String, Error> {
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<S
cmd.arg("-Z");
cmd.arg("unstable-options");
cmd.arg("--pretty=expanded");
let output = cmd.output().unwrap();
let output = cmd.output()?;
let src = from_utf8(&output.stdout).unwrap().to_owned();
let error = from_utf8(&output.stderr).unwrap().to_owned();
let src = from_utf8(&output.stdout)?.to_owned();
let error = from_utf8(&output.stderr)?.to_owned();
if src.len() == 0 {
Err(error)
Err(Error::Compile(error))
} else {
Ok(src)
}
@@ -44,8 +67,7 @@ pub fn expand(manifest_path: &Path, crate_name: &str, version: &str) -> Result<S
} else {
// Create a temp directory to use as a target dir for cargo expand, for
// hygenic purposes.
let target_dir = TempDir::new("cbindgen-expand")
.map_err(|_| format!("couldn't create a temp target directory"))?;
let target_dir = TempDir::new("cbindgen-expand")?;
run(target_dir.path())
}
+4 -4
View File
@@ -3,9 +3,9 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
mod cargo;
mod cargo_expand;
mod cargo_lock;
mod cargo_metadata;
mod cargo_toml;
pub(crate) mod cargo_expand;
pub(crate) mod cargo_lock;
pub(crate) mod cargo_metadata;
pub(crate) mod cargo_toml;
pub(crate) use self::cargo::*;
+40
View File
@@ -0,0 +1,40 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
use std::fmt;
pub use bindgen::cargo::cargo_metadata::Error as CargoMetadataError;
pub use bindgen::cargo::cargo_toml::Error as CargoTomlError;
pub use bindgen::cargo::cargo_expand::Error as CargoExpandError;
#[derive(Debug)]
pub enum Error {
CargoMetadata(String, CargoMetadataError),
CargoToml(String, CargoTomlError),
CargoExpand(String, CargoExpandError),
ParseSyntaxError{crate_name: String, src_path: String, message: String},
ParseCannotOpenFile{crate_name: String, src_path: String},
}
impl fmt::Display for Error {
fn fmt(&self, f: &mut fmt::Formatter) -> 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)
}
}
}
}
+2 -1
View File
@@ -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<Bindings, String> {
pub fn generate(mut self) -> Result<Bindings, Error> {
self.functions.sort_by(|x, y| x.name.cmp(&y.name));
self.transfer_annotations();
+2
View File
@@ -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;
+31 -22
View File
@@ -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<Parse, String>;
type ParseResult = Result<Parse, Error>;
/// 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<syn::Item>,
) -> 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<syn::Item>,
) -> Result<(), String> {
) -> Result<(), Error> {
self.out.load_syn_crate_mod(
&self.binding_crate_name,
&pkg.name,
+2 -2
View File
@@ -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<P: AsRef<Path>>(crate_dir: P) -> Result<Bindings, String> {
pub fn generate<P: AsRef<Path>>(crate_dir: P) -> Result<Bindings, Error> {
let config = Config::from_root_or_default(crate_dir.as_ref());
generate_with_config(crate_dir, config)
@@ -29,7 +29,7 @@ pub fn generate<P: AsRef<Path>>(crate_dir: P) -> Result<Bindings, String> {
pub fn generate_with_config<P: AsRef<Path>>(
crate_dir: P,
config: Config,
) -> Result<Bindings, String> {
) -> Result<Bindings, Error> {
Builder::new()
.with_config(config)
.with_crate(crate_dir)
+2 -2
View File
@@ -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<Bindings, String> {
fn load_bindings<'a>(input: &Path, matches: &ArgMatches<'a>) -> Result<Bindings, Error> {
// 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