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