Skip to content

Commit 00c9dfc

Browse files
committed
fix(macros): don't mutate environment variables
1 parent 91d26ba commit 00c9dfc

File tree

1 file changed

+49
-29
lines changed
  • sqlx-macros-core/src/query

1 file changed

+49
-29
lines changed

sqlx-macros-core/src/query/mod.rs

+49-29
Original file line numberDiff line numberDiff line change
@@ -111,37 +111,14 @@ static METADATA: Lazy<Mutex<HashMap<String, Metadata>>> = Lazy::new(Default::def
111111

112112
// If we are in a workspace, lookup `workspace_root` since `CARGO_MANIFEST_DIR` won't
113113
// reflect the workspace dir: https://github.com/rust-lang/cargo/issues/3946
114-
fn init_metadata(manifest_dir: &String) -> Metadata {
115-
let manifest_dir: PathBuf = manifest_dir.into();
114+
fn init_metadata(manifest_dir_str: &String) -> Metadata {
115+
let manifest_dir: PathBuf = manifest_dir_str.into();
116116

117-
// If a .env file exists at CARGO_MANIFEST_DIR, load environment variables from this,
118-
// otherwise fallback to default dotenv behaviour.
119-
let env_path = manifest_dir.join(".env");
120-
121-
#[cfg_attr(not(procmacro2_semver_exempt), allow(unused_variables))]
122-
let env_path = if env_path.exists() {
123-
// Load the new environment variables and override the old ones if necessary.
124-
let res = dotenvy::from_path_override(&env_path);
125-
if let Err(e) = res {
126-
panic!("failed to load environment from {env_path:?}, {e}");
127-
}
128-
129-
Some(env_path)
130-
} else {
131-
dotenvy::dotenv_override().ok()
132-
};
133-
134-
// tell the compiler to watch the `.env` for changes, if applicable
135-
#[cfg(procmacro2_semver_exempt)]
136-
if let Some(env_path) = env_path.as_ref().and_then(|path| path.to_str()) {
137-
proc_macro::tracked_path::path(env_path);
138-
}
139-
140-
let offline = env("SQLX_OFFLINE")
117+
let offline = env_with_fallback("SQLX_OFFLINE", Some(&manifest_dir_str))
141118
.map(|s| s.eq_ignore_ascii_case("true") || s == "1")
142119
.unwrap_or(false);
143120

144-
let database_url = env("DATABASE_URL").ok();
121+
let database_url = env_with_fallback("DATABASE_URL", Some(&manifest_dir_str));
145122

146123
Metadata {
147124
manifest_dir,
@@ -182,7 +159,7 @@ pub fn expand_input<'a>(
182159

183160
// Check SQLX_OFFLINE_DIR, then local .sqlx, then workspace .sqlx.
184161
let dirs = [
185-
|_: &Metadata| env("SQLX_OFFLINE_DIR").ok().map(PathBuf::from),
162+
|_: &Metadata| env_with_fallback("SQLX_OFFLINE_DIR", None).map(PathBuf::from),
186163
|meta: &Metadata| Some(meta.manifest_dir.join(".sqlx")),
187164
|meta: &Metadata| Some(meta.workspace_root().join(".sqlx")),
188165
];
@@ -360,7 +337,7 @@ where
360337
if !offline {
361338
// Only save query metadata if SQLX_OFFLINE_DIR is set manually or by `cargo sqlx prepare`.
362339
// Note: in a cargo workspace this path is relative to the root.
363-
if let Ok(dir) = env("SQLX_OFFLINE_DIR") {
340+
if let Some(dir) = env_with_fallback("SQLX_OFFLINE_DIR", None) {
364341
let path = PathBuf::from(&dir);
365342

366343
match fs::metadata(&path) {
@@ -402,3 +379,46 @@ fn env(name: &str) -> Result<String, std::env::VarError> {
402379
std::env::var(name)
403380
}
404381
}
382+
383+
/// Get the value of an environment variable, try .env file if the variable can't be found.
384+
fn env_with_fallback(name: &str, manifest_dir: Option<&str>) -> Option<String> {
385+
let manifest_dir: PathBuf = manifest_dir.map(Into::into).unwrap_or_else(|| {
386+
env("CARGO_MANIFEST_DIR")
387+
.expect("`CARGO_MANIFEST_DIR` must be set")
388+
.into()
389+
});
390+
391+
if let Ok(opt_env) = env(name) {
392+
return Some(opt_env);
393+
}
394+
395+
// If a .env file exists at CARGO_MANIFEST_DIR, read environment variables from this,
396+
// otherwise fallback to default dotenv file.
397+
let env_path = manifest_dir.join(".env");
398+
399+
#[cfg_attr(not(procmacro2_semver_exempt), allow(unused_variables))]
400+
let env_file = if env_path.exists() {
401+
match dotenvy::from_path_iter(&env_path) {
402+
Ok(iter) => iter,
403+
Err(e) => panic!("failed to load environment from {env_path:?}, {e}"),
404+
}
405+
} else {
406+
dotenvy::dotenv_iter().ok()?
407+
};
408+
409+
// tell the compiler to watch the `.env` for changes, if applicable
410+
#[cfg(procmacro2_semver_exempt)]
411+
if let Some(env_path) = env_path.as_ref().and_then(|path| path.to_str()) {
412+
proc_macro::tracked_path::path(env_path);
413+
}
414+
415+
for item in env_file {
416+
let Ok((key, value)) = item else {
417+
continue;
418+
};
419+
if key == name {
420+
return Some(value);
421+
}
422+
}
423+
None
424+
}

0 commit comments

Comments
 (0)