1
+ use std:: collections:: HashMap ;
1
2
use std:: path:: PathBuf ;
2
3
use std:: sync:: { Arc , Mutex } ;
3
4
use std:: { fs, io} ;
@@ -106,27 +107,28 @@ impl Metadata {
106
107
}
107
108
}
108
109
110
+ static METADATA : Lazy < Mutex < HashMap < String , Metadata > > > = Lazy :: new ( Default :: default) ;
111
+
109
112
// If we are in a workspace, lookup `workspace_root` since `CARGO_MANIFEST_DIR` won't
110
113
// reflect the workspace dir: https://github.com/rust-lang/cargo/issues/3946
111
- static METADATA : Lazy < Metadata > = Lazy :: new ( || {
112
- let manifest_dir: PathBuf = env ( "CARGO_MANIFEST_DIR" )
113
- . expect ( "`CARGO_MANIFEST_DIR` must be set" )
114
- . into ( ) ;
114
+ fn init_metadata ( manifest_dir : & String ) -> Metadata {
115
+ let manifest_dir: PathBuf = manifest_dir. into ( ) ;
115
116
116
117
// If a .env file exists at CARGO_MANIFEST_DIR, load environment variables from this,
117
118
// otherwise fallback to default dotenv behaviour.
118
119
let env_path = manifest_dir. join ( ".env" ) ;
119
120
120
121
#[ cfg_attr( not( procmacro2_semver_exempt) , allow( unused_variables) ) ]
121
122
let env_path = if env_path. exists ( ) {
122
- let res = dotenvy:: from_path ( & env_path) ;
123
+ // Load the new environment variables and override the old ones if necessary.
124
+ let res = dotenvy:: from_path_override ( & env_path) ;
123
125
if let Err ( e) = res {
124
126
panic ! ( "failed to load environment from {env_path:?}, {e}" ) ;
125
127
}
126
128
127
129
Some ( env_path)
128
130
} else {
129
- dotenvy:: dotenv ( ) . ok ( )
131
+ dotenvy:: dotenv_override ( ) . ok ( )
130
132
} ;
131
133
132
134
// tell the compiler to watch the `.env` for changes, if applicable
@@ -147,32 +149,46 @@ static METADATA: Lazy<Metadata> = Lazy::new(|| {
147
149
database_url,
148
150
workspace_root : Arc :: new ( Mutex :: new ( None ) ) ,
149
151
}
150
- } ) ;
152
+ }
151
153
152
154
pub fn expand_input < ' a > (
153
155
input : QueryMacroInput ,
154
156
drivers : impl IntoIterator < Item = & ' a QueryDriver > ,
155
157
) -> crate :: Result < TokenStream > {
156
- let data_source = match & * METADATA {
158
+ let manifest_dir = env ( "CARGO_MANIFEST_DIR" ) . expect ( "`CARGO_MANIFEST_DIR` must be set" ) ;
159
+
160
+ let mut metadata_lock = METADATA
161
+ . lock ( )
162
+ // Just reset the metadata on error
163
+ . unwrap_or_else ( |poison_err| {
164
+ let mut guard = poison_err. into_inner ( ) ;
165
+ * guard = Default :: default ( ) ;
166
+ guard
167
+ } ) ;
168
+
169
+ let metadata = metadata_lock
170
+ . entry ( manifest_dir)
171
+ . or_insert_with_key ( init_metadata) ;
172
+
173
+ let data_source = match & metadata {
157
174
Metadata {
158
175
offline : false ,
159
176
database_url : Some ( db_url) ,
160
177
..
161
178
} => QueryDataSource :: live ( db_url) ?,
162
-
163
179
Metadata { offline, .. } => {
164
180
// Try load the cached query metadata file.
165
181
let filename = format ! ( "query-{}.json" , hash_string( & input. sql) ) ;
166
182
167
183
// Check SQLX_OFFLINE_DIR, then local .sqlx, then workspace .sqlx.
168
184
let dirs = [
169
- || env ( "SQLX_OFFLINE_DIR" ) . ok ( ) . map ( PathBuf :: from) ,
170
- || Some ( METADATA . manifest_dir . join ( ".sqlx" ) ) ,
171
- || Some ( METADATA . workspace_root ( ) . join ( ".sqlx" ) ) ,
185
+ |_ : & Metadata | env ( "SQLX_OFFLINE_DIR" ) . ok ( ) . map ( PathBuf :: from) ,
186
+ |meta : & Metadata | Some ( meta . manifest_dir . join ( ".sqlx" ) ) ,
187
+ |meta : & Metadata | Some ( meta . workspace_root ( ) . join ( ".sqlx" ) ) ,
172
188
] ;
173
189
let Some ( data_file_path) = dirs
174
190
. iter ( )
175
- . filter_map ( |path| path ( ) )
191
+ . filter_map ( |path| path ( metadata ) )
176
192
. map ( |path| path. join ( & filename) )
177
193
. find ( |path| path. exists ( ) )
178
194
else {
@@ -184,7 +200,6 @@ pub fn expand_input<'a>(
184
200
} . into ( )
185
201
) ;
186
202
} ;
187
-
188
203
QueryDataSource :: Cached ( DynQueryData :: from_data_file ( & data_file_path, & input. sql ) ?)
189
204
}
190
205
} ;
0 commit comments