add cargo manifest reflection
Signed-off-by: Jason Volk <jason@zemos.net>
This commit is contained in:
parent
f014231644
commit
936d2915e2
|
@ -472,6 +472,16 @@ dependencies = [
|
|||
"pkg-config",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "cargo_toml"
|
||||
version = "0.20.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ad639525b1c67b6a298f378417b060fbc04618bea559482a8484381cce27d965"
|
||||
dependencies = [
|
||||
"serde",
|
||||
"toml",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "cc"
|
||||
version = "1.1.6"
|
||||
|
@ -666,8 +676,10 @@ dependencies = [
|
|||
"argon2",
|
||||
"axum 0.7.5",
|
||||
"bytes",
|
||||
"cargo_toml",
|
||||
"checked_ops",
|
||||
"chrono",
|
||||
"conduit_macros",
|
||||
"const-str",
|
||||
"either",
|
||||
"figment",
|
||||
|
|
|
@ -28,6 +28,10 @@ name = "conduit"
|
|||
[workspace.dependencies.const-str]
|
||||
version = "0.5.7"
|
||||
|
||||
[workspace.dependencies.cargo_toml]
|
||||
version = "0.20"
|
||||
features = ["features"]
|
||||
|
||||
[workspace.dependencies.sanitize-filename]
|
||||
version = "0.5.0"
|
||||
|
||||
|
|
|
@ -53,8 +53,10 @@ sha256_media = []
|
|||
argon2.workspace = true
|
||||
axum.workspace = true
|
||||
bytes.workspace = true
|
||||
cargo_toml.workspace = true
|
||||
checked_ops.workspace = true
|
||||
chrono.workspace = true
|
||||
conduit-macros.workspace = true
|
||||
const-str.workspace = true
|
||||
either.workspace = true
|
||||
figment.workspace = true
|
||||
|
|
|
@ -55,6 +55,8 @@ pub enum Error {
|
|||
Http(#[from] http::Error),
|
||||
#[error("{0}")]
|
||||
HttpHeader(#[from] http::header::InvalidHeaderValue),
|
||||
#[error("{0}")]
|
||||
CargoToml(#[from] cargo_toml::Error),
|
||||
|
||||
// ruma
|
||||
#[error("{0}")]
|
||||
|
|
|
@ -0,0 +1,66 @@
|
|||
//! Information about the build related to Cargo. This is a frontend interface
|
||||
//! informed by proc-macros that capture raw information at build time which is
|
||||
//! further processed at runtime either during static initialization or as
|
||||
//! necessary.
|
||||
|
||||
use std::sync::OnceLock;
|
||||
|
||||
use cargo_toml::Manifest;
|
||||
use conduit_macros::cargo_manifest;
|
||||
|
||||
use crate::Result;
|
||||
|
||||
// Raw captures of the cargo manifest for each crate. This is provided by a
|
||||
// proc-macro at build time since the source directory and the cargo toml's may
|
||||
// not be present during execution.
|
||||
|
||||
#[cargo_manifest]
|
||||
const WORKSPACE_MANIFEST: &'static str = ();
|
||||
#[cargo_manifest("macros")]
|
||||
const MACROS_MANIFEST: &'static str = ();
|
||||
#[cargo_manifest("core")]
|
||||
const CORE_MANIFEST: &'static str = ();
|
||||
#[cargo_manifest("database")]
|
||||
const DATABASE_MANIFEST: &'static str = ();
|
||||
#[cargo_manifest("service")]
|
||||
const SERVICE_MANIFEST: &'static str = ();
|
||||
#[cargo_manifest("admin")]
|
||||
const ADMIN_MANIFEST: &'static str = ();
|
||||
#[cargo_manifest("router")]
|
||||
const ROUTER_MANIFEST: &'static str = ();
|
||||
#[cargo_manifest("main")]
|
||||
const MAIN_MANIFEST: &'static str = ();
|
||||
|
||||
/// Processed list of features access all project crates. This is generated from
|
||||
/// the data in the MANIFEST strings and contains all possible project features.
|
||||
/// For *enabled* features see the info::rustc module instead.
|
||||
static FEATURES: OnceLock<Vec<String>> = OnceLock::new();
|
||||
|
||||
/// List of all possible features for the project. For *enabled* features in
|
||||
/// this build see the companion function in info::rustc.
|
||||
pub fn features() -> &'static Vec<String> {
|
||||
FEATURES.get_or_init(|| init_features().unwrap_or_else(|e| panic!("Failed initialize features: {e}")))
|
||||
}
|
||||
|
||||
fn init_features() -> Result<Vec<String>> {
|
||||
let mut features = Vec::new();
|
||||
append_features(&mut features, WORKSPACE_MANIFEST)?;
|
||||
append_features(&mut features, MACROS_MANIFEST)?;
|
||||
append_features(&mut features, CORE_MANIFEST)?;
|
||||
append_features(&mut features, DATABASE_MANIFEST)?;
|
||||
append_features(&mut features, SERVICE_MANIFEST)?;
|
||||
append_features(&mut features, ADMIN_MANIFEST)?;
|
||||
append_features(&mut features, ROUTER_MANIFEST)?;
|
||||
append_features(&mut features, MAIN_MANIFEST)?;
|
||||
features.sort();
|
||||
features.dedup();
|
||||
|
||||
Ok(features)
|
||||
}
|
||||
|
||||
fn append_features(features: &mut Vec<String>, manifest: &str) -> Result<()> {
|
||||
let manifest = Manifest::from_str(manifest)?;
|
||||
features.extend(manifest.features.keys().cloned());
|
||||
|
||||
Ok(())
|
||||
}
|
|
@ -1,4 +1,5 @@
|
|||
//! Information about the project. This module contains version, build, system,
|
||||
//! etc information which can be queried by admins or used by developers.
|
||||
|
||||
pub mod cargo;
|
||||
pub mod version;
|
||||
|
|
|
@ -0,0 +1,51 @@
|
|||
use std::{fs::read_to_string, path::PathBuf};
|
||||
|
||||
use proc_macro::TokenStream;
|
||||
use quote::quote;
|
||||
use syn::{parse_macro_input, AttributeArgs, ItemConst, Lit, NestedMeta};
|
||||
|
||||
pub(super) fn manifest(args: TokenStream, item: TokenStream) -> TokenStream {
|
||||
let item = parse_macro_input!(item as ItemConst);
|
||||
let args = parse_macro_input!(args as AttributeArgs);
|
||||
let member = args.into_iter().find_map(|arg| {
|
||||
let NestedMeta::Lit(arg) = arg else {
|
||||
return None;
|
||||
};
|
||||
let Lit::Str(arg) = arg else {
|
||||
return None;
|
||||
};
|
||||
Some(arg.value())
|
||||
});
|
||||
|
||||
let path = manifest_path(member.as_deref());
|
||||
let manifest = read_to_string(&path).unwrap_or_default();
|
||||
|
||||
let name = item.ident;
|
||||
let val = manifest.as_str();
|
||||
let ret = quote! {
|
||||
const #name: &'static str = #val;
|
||||
};
|
||||
|
||||
ret.into()
|
||||
}
|
||||
|
||||
#[allow(clippy::option_env_unwrap)]
|
||||
fn manifest_path(member: Option<&str>) -> PathBuf {
|
||||
let mut path: PathBuf = option_env!("CARGO_MANIFEST_DIR")
|
||||
.expect("missing CARGO_MANIFEST_DIR in environment")
|
||||
.into();
|
||||
|
||||
// conduwuit/src/macros/ -> conduwuit/src/
|
||||
path.pop();
|
||||
|
||||
if let Some(member) = member {
|
||||
// conduwuit/$member/Cargo.toml
|
||||
path.push(member);
|
||||
} else {
|
||||
// conduwuit/src/ -> conduwuit/
|
||||
path.pop();
|
||||
}
|
||||
|
||||
path.push("Cargo.toml");
|
||||
path
|
||||
}
|
|
@ -1,4 +1,5 @@
|
|||
mod admin;
|
||||
mod cargo;
|
||||
mod utils;
|
||||
|
||||
use proc_macro::TokenStream;
|
||||
|
@ -7,3 +8,6 @@ use proc_macro::TokenStream;
|
|||
pub fn admin_command_dispatch(args: TokenStream, input: TokenStream) -> TokenStream {
|
||||
admin::command_dispatch(args, input)
|
||||
}
|
||||
|
||||
#[proc_macro_attribute]
|
||||
pub fn cargo_manifest(args: TokenStream, input: TokenStream) -> TokenStream { cargo::manifest(args, input) }
|
||||
|
|
Loading…
Reference in New Issue