Skip to content

Commit

Permalink
feat: allow users to specify a crate version for bindings generation
Browse files Browse the repository at this point in the history
- this is useful in a setting where several crates may share the same name
in e.g. a semver trick setting https://github.com/dtolnay/semver-trick to
allow adding compatibility code to older versions of a crate to allow users
to migrate towards newer version of a crate
- this is a pure addition and should keep all existing behaviors exactly
the same
  • Loading branch information
IceTDrinker committed Nov 15, 2023
1 parent 6bfc217 commit 4877deb
Show file tree
Hide file tree
Showing 3 changed files with 51 additions and 2 deletions.
10 changes: 10 additions & 0 deletions src/bindgen/builder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ pub struct Builder {
config: Config,
srcs: Vec<path::PathBuf>,
lib: Option<(path::PathBuf, Option<String>)>,
lib_version: Option<String>,
lib_cargo: Option<Cargo>,
std_types: bool,
lockfile: Option<path::PathBuf>,
Expand All @@ -29,6 +30,7 @@ impl Builder {
config: Config::default(),
srcs: Vec::new(),
lib: None,
lib_version: None,
lib_cargo: None,
std_types: true,
lockfile: None,
Expand Down Expand Up @@ -313,6 +315,13 @@ impl Builder {
self
}

#[allow(unused)]
pub fn with_crate_version(mut self, lib_version_str: &str) -> Builder {
debug_assert!(self.lib_version.is_none());
self.lib_version = Some(lib_version_str.to_owned());
self
}

#[allow(unused)]
pub fn with_crate_and_name<P: AsRef<path::Path>, S: AsRef<str>>(
mut self,
Expand Down Expand Up @@ -381,6 +390,7 @@ impl Builder {
&lib_dir,
lockfile,
binding_lib_name.as_deref(),
self.lib_version.as_deref(),
self.config.parse.parse_deps,
self.config.parse.clean,
self.config.only_target_dependencies,
Expand Down
30 changes: 28 additions & 2 deletions src/bindgen/cargo/cargo.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ fn parse_dep_string(dep_string: &str) -> (&str, Option<&str>) {
pub(crate) struct Cargo {
manifest_path: PathBuf,
binding_crate_name: String,
binding_crate_version: Option<String>,
lock: Option<Lock>,
metadata: Metadata,
clean: bool,
Expand All @@ -38,6 +39,7 @@ impl Cargo {
crate_dir: &Path,
lock_file: Option<&str>,
binding_crate_name: Option<&str>,
binding_crate_version: Option<&str>,
use_cargo_lock: bool,
clean: bool,
only_target_dependencies: bool,
Expand Down Expand Up @@ -73,9 +75,12 @@ impl Cargo {
}
};

let binding_crate_version = binding_crate_version.map(|s| s.to_owned());

Ok(Cargo {
manifest_path: toml_path,
binding_crate_name,
binding_crate_version,
lock,
metadata,
clean,
Expand Down Expand Up @@ -181,11 +186,32 @@ impl Cargo {
}

/// Finds the package reference in `cargo metadata` that has `package_name`
/// ignoring the version.
/// ignoring the version if it was not requested explicitely.
fn find_pkg_ref(&self, package_name: &str) -> Option<PackageRef> {
for package in &self.metadata.packages {
if package.name_and_version.name == package_name {
return Some(package.name_and_version.clone());
match (
&self.binding_crate_version,
&package.name_and_version.version,
) {
(Some(requested_version), Some(found_package_version)) => {
if requested_version.as_str() == found_package_version.as_str() {
// We found the package matching the name and requested version, return
// it
return Some(package.name_and_version.clone());
} else {
// Found a package with the same name but a different version continue.
continue;
}
}
// A version was requested, but the found package does not have a version, so
// keep looking
(Some(_), None) => continue,
// No version requested, return the found package
// Note that this has random behavior if more than one package found in cargo
// metadata have the same name
(None, _) => return Some(package.name_and_version.clone()),
}
}
}
None
Expand Down
13 changes: 13 additions & 0 deletions src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,7 @@ fn load_bindings(input: &Path, matches: &ArgMatches) -> Result<Bindings, Error>
input,
matches.value_of("lockfile"),
matches.value_of("crate"),
matches.value_of("crate-version"),
true,
matches.is_present("clean"),
matches.is_present("only-target-dependencies"),
Expand Down Expand Up @@ -215,6 +216,18 @@ fn main() {
)
.required(false),
)
.arg(
Arg::new("crate-version")
.long("crate-version")
.value_name("CRATE_VERSION")
.help(
"If generating bindings for a crate, \
the specific version of the crate to generate bindings for. \
This option is useful if a dependency shares the same name \
as the current project helping disambiguate which crate is targeted.",
)
.required(false),
)
.arg(
Arg::new("out")
.short('o')
Expand Down

0 comments on commit 4877deb

Please sign in to comment.