@@ -111,37 +111,14 @@ static METADATA: Lazy<Mutex<HashMap<String, Metadata>>> = Lazy::new(Default::def
111
111
112
112
// If we are in a workspace, lookup `workspace_root` since `CARGO_MANIFEST_DIR` won't
113
113
// 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 ( ) ;
116
116
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) )
141
118
. map ( |s| s. eq_ignore_ascii_case ( "true" ) || s == "1" )
142
119
. unwrap_or ( false ) ;
143
120
144
- let database_url = env ( "DATABASE_URL" ) . ok ( ) ;
121
+ let database_url = env_with_fallback ( "DATABASE_URL" , Some ( & manifest_dir_str ) ) ;
145
122
146
123
Metadata {
147
124
manifest_dir,
@@ -182,7 +159,7 @@ pub fn expand_input<'a>(
182
159
183
160
// Check SQLX_OFFLINE_DIR, then local .sqlx, then workspace .sqlx.
184
161
let dirs = [
185
- |_: & Metadata | env ( "SQLX_OFFLINE_DIR" ) . ok ( ) . map ( PathBuf :: from) ,
162
+ |_: & Metadata | env_with_fallback ( "SQLX_OFFLINE_DIR" , None ) . map ( PathBuf :: from) ,
186
163
|meta : & Metadata | Some ( meta. manifest_dir . join ( ".sqlx" ) ) ,
187
164
|meta : & Metadata | Some ( meta. workspace_root ( ) . join ( ".sqlx" ) ) ,
188
165
] ;
@@ -360,7 +337,7 @@ where
360
337
if !offline {
361
338
// Only save query metadata if SQLX_OFFLINE_DIR is set manually or by `cargo sqlx prepare`.
362
339
// 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 ) {
364
341
let path = PathBuf :: from ( & dir) ;
365
342
366
343
match fs:: metadata ( & path) {
@@ -402,3 +379,46 @@ fn env(name: &str) -> Result<String, std::env::VarError> {
402
379
std:: env:: var ( name)
403
380
}
404
381
}
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