1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100
//LICENSE Portions Copyright 2019-2021 ZomboDB, LLC.
//LICENSE
//LICENSE Portions Copyright 2021-2023 Technology Concepts & Design, Inc.
//LICENSE
//LICENSE Portions Copyright 2023-2023 PgCentral Foundation, Inc. <contact@pgcentral.org>
//LICENSE
//LICENSE All rights reserved.
//LICENSE
//LICENSE Use of this source code is governed by the MIT license that can be found in the LICENSE file.
use std::path::Path;
use cargo_toml::Manifest;
use eyre::eyre;
/// Extension to `cargo_toml::Manifest`.
/// Import by adding `use pgrx_pg_config::cargo::PgrxManifestExt;`
/// and extended functions will be available on `Manifest` values.
pub trait PgrxManifestExt {
/// Package name
fn package_name(&self) -> eyre::Result<String>;
/// Package version
fn package_version(&self) -> eyre::Result<String>;
/// Resolved string for target library name, either its lib.name,
/// or package name with hyphens replaced with underscore.
/// https://doc.rust-lang.org/cargo/reference/cargo-targets.html#the-name-field
fn lib_name(&self) -> eyre::Result<String>;
/// Resolved string for target artifact name, used for matching on
/// `cargo_metadata::message::Artifact`.
fn target_name(&self) -> eyre::Result<String>;
/// Resolved string for target library name extension filename
fn lib_filename(&self) -> eyre::Result<String>;
}
impl PgrxManifestExt for Manifest {
fn package_name(&self) -> eyre::Result<String> {
match &self.package {
Some(package) => Ok(package.name.to_owned()),
None => Err(eyre!("Could not get [package] from manifest.")),
}
}
fn package_version(&self) -> eyre::Result<String> {
match &self.package {
Some(package) => match &package.version {
cargo_toml::Inheritable::Set(version) => Ok(version.to_owned()),
// This should be impossible to hit, since we use
// `Manifest::from_path`, which calls `complete_from_path`,
// which is documented as resolving these. That said, I
// haven't tested it, and it's not clear how much it
// actually matters either way, so we just emit an error
// rather than doing something like `unreachable!()`.
cargo_toml::Inheritable::Inherited { workspace: _ } => {
Err(eyre!("Workspace-inherited package version are not currently supported."))
}
},
None => Err(eyre!("Could not get [package] from manifest.")),
}
}
fn lib_name(&self) -> eyre::Result<String> {
match &self.package {
Some(_) => match &self.lib {
Some(lib) => match &lib.name {
// `cargo_manifest` auto fills lib.name with package.name;
// hyphen replaced with underscore if crate type is lib.
// So we will always have a lib.name for lib crates.
Some(lib_name) => Ok(lib_name.to_owned()),
None => Err(eyre!("Could not get [lib] name from manifest.")),
},
None => Err(eyre!("Could not get [lib] name from manifest.")),
},
None => Err(eyre!("Could not get [lib] name from manifest.")),
}
}
fn target_name(&self) -> eyre::Result<String> {
let package = self.package_name()?;
let lib = self.lib_name()?;
if package.replace('-', "_") == lib {
Ok(package)
} else {
Ok(lib)
}
}
fn lib_filename(&self) -> eyre::Result<String> {
let lib_name = &self.lib_name()?;
let so_extension = if cfg!(target_os = "macos") { "dylib" } else { "so" };
Ok(format!("lib{}.{}", lib_name.replace('-', "_"), so_extension))
}
}
/// Helper functions to read `Cargo.toml` and remap error to `eyre::Result`.
pub fn read_manifest<T: AsRef<Path>>(path: T) -> eyre::Result<Manifest> {
Manifest::from_path(path).map_err(|err| eyre!("Couldn't parse manifest: {}", err))
}