From e8abd9f79a1d30fb77807567c5c9b02d48761f1e Mon Sep 17 00:00:00 2001 From: Matt Keeter Date: Tue, 23 Jun 2026 14:49:48 -0400 Subject: [PATCH 1/2] Read env var in proc-macro generated code --- Cargo.lock | 2 +- lib/task-config/Cargo.toml | 2 +- lib/task-config/src/lib.rs | 44 ++++++++++++++++++++++++-------------- 3 files changed, 30 insertions(+), 18 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 1e6edb623..385e72479 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -5879,12 +5879,12 @@ dependencies = [ name = "task-config" version = "0.1.0" dependencies = [ - "build-util", "proc-macro2", "quote", "serde", "syn 2.0.106", "toml 1.1.2+spec-1.1.0", + "toml-task", ] [[package]] diff --git a/lib/task-config/Cargo.toml b/lib/task-config/Cargo.toml index 3fa8cc07b..bc69ea0e2 100644 --- a/lib/task-config/Cargo.toml +++ b/lib/task-config/Cargo.toml @@ -9,7 +9,7 @@ quote = { workspace = true } serde = { workspace = true } syn = { workspace = true } toml = { workspace = true } -build-util = { path = "../../build/util" } +toml-task = { path = "../../lib/toml-task" } [lib] proc-macro = true diff --git a/lib/task-config/src/lib.rs b/lib/task-config/src/lib.rs index 10e6aaa9f..dba0b2f87 100644 --- a/lib/task-config/src/lib.rs +++ b/lib/task-config/src/lib.rs @@ -142,7 +142,7 @@ fn config_to_token( /// cannot be configured using this macro). #[proc_macro] pub fn task_config(tokens: TokenStream) -> TokenStream { - let config = build_util::task_config::().unwrap(); + let config = get_task_config().expect("task config is missing"); let input = parse_macro_input!(tokens as Config); let fields = input.items.iter(); @@ -160,14 +160,13 @@ pub fn task_config(tokens: TokenStream) -> TokenStream { }) .collect::>(); - let app_toml_path = std::env::var("HUBRIS_APP_TOML") - .expect("Could not find 'HUBRIS_APP_TOML' environment variable"); - // Once `proc_macro::tracked_env::var` is stable, we won't need to use - // this hack, but until then, we include the app TOML file to force + // this hack, but until then, we include the environment variable to force // rebuilds if it changes (and trust it's optimized out by the compiler) quote! { - const APP_TOML_TO_ENSURE_REBUILD: &[u8] = include_bytes!(#app_toml_path); + mod _hidden { + pub const _REBUILDER: &'static str = core::env!("HUBRIS_TASK_CONFIG"); + } struct Config { #(#fields),* } @@ -185,10 +184,7 @@ pub fn task_config(tokens: TokenStream) -> TokenStream { pub fn optional_task_config(tokens: TokenStream) -> TokenStream { let input = parse_macro_input!(tokens as Config); let fields = input.items.iter(); - let app_toml_path = std::env::var("HUBRIS_APP_TOML") - .expect("Could not find 'HUBRIS_APP_TOML' environment variable"); - - let cfg_val = if let Ok(config) = build_util::task_config::() { + let cfg_val = if let Some(config) = get_task_config() { let values = input .items .iter() @@ -201,10 +197,6 @@ pub fn optional_task_config(tokens: TokenStream) -> TokenStream { quote! { #ident: #vs } }) .collect::>(); - - // Once `proc_macro::tracked_env::var` is stable, we won't need to use - // this hack, but until then, we include the app TOML file to force - // rebuilds if it changes (and trust it's optimized out by the compiler) quote! { Some(Config { #(#values),* @@ -214,10 +206,12 @@ pub fn optional_task_config(tokens: TokenStream) -> TokenStream { quote! { None } }; // Once `proc_macro::tracked_env::var` is stable, we won't need to use - // this hack, but until then, we include the app TOML file to force + // this hack, but until then, we include the environment variable to force // rebuilds if it changes (and trust it's optimized out by the compiler) quote! { - const APP_TOML_TO_ENSURE_REBUILD: &[u8] = include_bytes!(#app_toml_path); + mod _hidden { + pub const _REBUILDER: &'static str = core::env!("HUBRIS_TASK_CONFIG"); + } struct Config { #(#fields),* } @@ -225,3 +219,21 @@ pub fn optional_task_config(tokens: TokenStream) -> TokenStream { } .into() } + +/// Gets a task config from `HUBRIS_TASK_CONFIG` +/// +/// Note that this is used instead of `build_utils::task_config`; the functions +/// in `build_utils` print a `cargo::rerun-if-env-changed` message, which isn't +/// valid in a proc_macro context. +/// +/// # Panics +/// If the environment variable is missing or the task TOML cannot be parsed +fn get_task_config() -> Option { + let config = std::env::var("HUBRIS_TASK_CONFIG") + .map_err(|e| format!("could not read HUBRIS_TASK_CONFIG: {e:#}")) + .unwrap(); + toml::from_str::>(&config) + .map_err(|e| format!("could not deserialize configuration: {e:#}")) + .unwrap() + .config +} From 7d9d9226de4f3147209f32a1815adf47cc54a236 Mon Sep 17 00:00:00 2001 From: Matt Keeter Date: Mon, 29 Jun 2026 16:42:22 -0400 Subject: [PATCH 2/2] Remove unnecessary `pub` --- lib/task-config/src/lib.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/task-config/src/lib.rs b/lib/task-config/src/lib.rs index dba0b2f87..8082e1d91 100644 --- a/lib/task-config/src/lib.rs +++ b/lib/task-config/src/lib.rs @@ -165,7 +165,7 @@ pub fn task_config(tokens: TokenStream) -> TokenStream { // rebuilds if it changes (and trust it's optimized out by the compiler) quote! { mod _hidden { - pub const _REBUILDER: &'static str = core::env!("HUBRIS_TASK_CONFIG"); + const _REBUILDER: &'static str = core::env!("HUBRIS_TASK_CONFIG"); } struct Config { #(#fields),* @@ -210,7 +210,7 @@ pub fn optional_task_config(tokens: TokenStream) -> TokenStream { // rebuilds if it changes (and trust it's optimized out by the compiler) quote! { mod _hidden { - pub const _REBUILDER: &'static str = core::env!("HUBRIS_TASK_CONFIG"); + const _REBUILDER: &'static str = core::env!("HUBRIS_TASK_CONFIG"); } struct Config { #(#fields),*