diff --git a/perlmod-macro/src/attribs.rs b/perlmod-macro/src/attribs.rs index 7c77fab..60c662b 100644 --- a/perlmod-macro/src/attribs.rs +++ b/perlmod-macro/src/attribs.rs @@ -26,11 +26,11 @@ impl TryFrom for ModuleAttrs { .. })) => { if path.is_ident("name") { - package_name = Some(litstr.value()); + package_name = Some(expand_env_vars(&litstr)?); } else if path.is_ident("file") { - file_name = Some(litstr.value()); + file_name = Some(expand_env_vars(&litstr)?); } else if path.is_ident("lib") { - lib_name = Some(litstr.value()); + lib_name = Some(expand_env_vars(&litstr)?); } else { bail!(path => "unknown argument"); } @@ -50,6 +50,39 @@ impl TryFrom for ModuleAttrs { } } +fn expand_env_vars(lit_str: &syn::LitStr) -> Result { + let input = lit_str.value(); + let mut expanded = String::with_capacity(input.len()); + + let mut input = input.as_str(); + loop { + let dollar = match input.find("${") { + Some(d) => d, + None => { + expanded.push_str(input); + break; + } + }; + + expanded.push_str(&input[..dollar]); + input = &input[(dollar + 2)..]; + + let end = input.find('}').ok_or_else( + || format_err!(lit_str => "missing end of environment variable expansion"), + )?; + + let var_name = &input[..end]; + input = &input[(end + 1)..]; + + let var = std::env::var(var_name).map_err(|err| { + format_err!(lit_str => "failed to expand environment variable {:?}: {}", var_name, err) + })?; + expanded.push_str(&var); + } + + Ok(expanded) +} + impl ModuleAttrs { pub fn mangle_package_name(&self) -> String { let mut out = String::with_capacity(self.package_name.len()); diff --git a/perlmod-macro/src/lib.rs b/perlmod-macro/src/lib.rs index e330fdd..3ade596 100644 --- a/perlmod-macro/src/lib.rs +++ b/perlmod-macro/src/lib.rs @@ -51,6 +51,8 @@ fn handle_error(mut item: TokenStream, data: Result) -> Toke /// ``` /// // 'lib' and 'file' are optional. We use 'file' here to prevent doc tests from writing out the /// // file. +/// // +/// // 'name', 'lib' and 'file' expand environment variables such as `${CARGO_PKG_NAME}` /// #[perlmod::package(name = "RSPM::Foo", lib = "perlmod_test", file = "/dev/null")] /// mod an_unused_name { /// use anyhow::{bail, Error}; diff --git a/perlmod-test/src/pkg142.rs b/perlmod-test/src/pkg142.rs index 9d0e48b..f6aa704 100644 --- a/perlmod-test/src/pkg142.rs +++ b/perlmod-test/src/pkg142.rs @@ -34,3 +34,14 @@ mod export { Ok(value.0) } } + +#[perlmod::package(name = "RSPM::EnvVarLibrary", lib = "x-${CARGO_PKG_NAME}-y")] +mod expanded_export { + use anyhow::Error; + + #[export] + fn test_lib_env_vars(value: &str) -> Result<(), Error> { + println!("foo: {:?}", value); + Ok(()) + } +}